__COUNTER__如何在此处导致ODR违规?

时间:2016-05-17 06:29:27

标签: c++ c-preprocessor one-definition-rule

this presentation 大约00:19:00,Andrei Alexandrescu解释了他的SCOPE_EXIT宏的实现。他在堆栈上创建了一个ScopeGuard对象,在销毁时执行lambda:

#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() + [&]()

到目前为止,众所周知(他甚至在他的幻灯片中说这是一顶旧帽子)。用法如下:

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

但是在01:04:00,Chandler Carruth声称使用__COUNTER__宏来创建一个匿名的#34;在内联函数中使用时,name会导致ODR违规。这可能是真的吗?该宏仅用于创建本地变量名称,而不是类型名称或其他内容,因此如何导致ODR违规?

1 个答案:

答案 0 :(得分:9)

假设内联函数位于两个不同翻译单元中的标题中,并且计数器的值恰好在每个翻译单元中都有不同的值。

然后,您有两个内联函数的定义,它们具有不同的变量名称。这是ODR违规 - 你必须为每个定义使用相同的令牌序列。

(虽然在实践中如果它引起任何问题我会感到非常惊讶。)