【问题标题】:How can __COUNTER__ cause a ODR-violation here?__COUNTER__ 如何在此处导致 ODR 违规?
【发布时间】:2016-09-13 02:45:06
【问题描述】:

在 00:19:00 左右的 this presentation 中,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__ 宏来创建“匿名”名称时,会导致 ODR 违规。这是真的吗?宏只用来创建局部变量名,不是类型名什么的,怎么会导致ODR违规呢?

【问题讨论】:

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


    【解决方案1】:

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

    那么你有两个内联函数的定义,变量的名称不同。这违反了 ODR - 您必须为每个定义使用相同的标记序列。

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

    【讨论】:

    • 我刚刚得出了同样的结论,我花了一段时间才意识到这是关于函数本身的定义。但是,这是有道理的,即使它只是一个不同的变量名。我想人们只能希望这不会造成任何问题......也许 LINE 宏在这里会是一个更好的选择?
    • 是的,除非您想在一行中声明多个这些内容。 (或者你在搞乱#line。)
    猜你喜欢
    • 2011-11-29
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多