Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can __COUNTER__ cause a ODR-violation here?

In this presentation at around 00:19:00, Andrei Alexandrescu explains the implementation of his SCOPE_EXIT macro. He creates a ScopeGuard object on the stack that executes a lambda on destruction:

#define ANONYMOUS_VARIABLE(str) \
    CONCATENATE(str, __COUNTER__)

namespace detail {
    enum class ScopeGuardOnExit {};
    template <typename Fun>
    ScopeGuard<Fun>
    operator+(ScopeGuardOnExit, Fun&& fn) {
        return ScopeGuard<Fun>(std::forward<Fun>(fn));
    }
}

#define SCOPE_EXIT \
    auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
    = ::detail::ScopeGuardOnExit() + [&]()

So far, so well known (he even states in his slides that this is an old hat). The usage looks like this:

void foo()
{
    SCOPE_EXIT{ printf("foo exits"); };
}

But at 01:04:00, Chandler Carruth claims that this usage of the __COUNTER__ macro to create an "anonymous" name would cause an ODR violation when used in an inline function. Can this be true? The macro is only used to create a local variable name, not a type name or something, so how could this cause an ODR violation?

like image 724
Horstling Avatar asked May 17 '16 06:05

Horstling


1 Answers

Suppose the inline function is in a header included in two different translation units, and the value of the counter happens to be at a different value in each.

Then you have two definitions of the inline function with different names for the variable. That's an ODR violation - you have to use the same sequence of tokens for every definition.

(Although in practice I'd be very surprised if it caused any problem.)

like image 131
Alan Stokes Avatar answered Oct 17 '22 06:10

Alan Stokes