__COUNTER__ 怎么会在这里导致 ODR 违规?
How can __COUNTER__ cause a ODR-violation here?
在 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__
宏来创建 "anonymous" 名称会在内联函数中使用时导致 ODR 违规。这是真的吗?该宏仅用于创建局部变量名称,而不是类型名称或其他名称,所以这怎么会导致 ODR 违规?
假设内联函数在 header 中包含在两个不同的翻译单元中,并且计数器的值恰好在每个中处于不同的值。
然后你有两个内联函数的定义,它们的变量名称不同。这是 ODR 违规行为 - 您必须为每个定义使用相同的标记序列。
(尽管在实践中如果它引起任何问题我会感到非常惊讶。)
在 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__
宏来创建 "anonymous" 名称会在内联函数中使用时导致 ODR 违规。这是真的吗?该宏仅用于创建局部变量名称,而不是类型名称或其他名称,所以这怎么会导致 ODR 违规?
假设内联函数在 header 中包含在两个不同的翻译单元中,并且计数器的值恰好在每个中处于不同的值。
然后你有两个内联函数的定义,它们的变量名称不同。这是 ODR 违规行为 - 您必须为每个定义使用相同的标记序列。
(尽管在实践中如果它引起任何问题我会感到非常惊讶。)