模板实例化期间第二次传递名称查找的静态命名空间与匿名命名空间的区别
difference in static vs anonymous namespace for second pass name lookup during template instantiation
我 long 自从停止将 static
用于辅助函数以支持匿名命名空间以来,它具有使用类型、变量和模板的优势以及功能。
但是,当我用包装器模板替换对它的调用时找不到函数时,我感到很惊讶。使用与我的项目匹配的编译器和选项查看 https://godbolt.org/z/GrojceqGx 处的代码。
#include <utility>
//#define WORKING
class C {};
template <typename Left, typename Right>
auto wrapper (Left&& left, Right&& right, const char* name)
{
return foo (std::forward<Left>(left),std::forward<Right>(right));
}
#ifdef WORKING
static
void foo (C& left, int right)
{
// compiles when using static function
}
#else
namespace {
void foo (C& left, int right)
{
// fails to compile in anonymous namespace
}
}
#endif
void sample()
{
C x;
wrapper (x, 17, "call 1");
}
为什么 wrapper
的实例化在 static
时看到 foo
而在匿名命名空间中却看不到?实例化点在这个翻译单元中,无论哪种方式都在同一个地方。
因为不管你信不信,匿名命名空间完全是另一个命名空间。而不是全局命名空间。
当您使用 static
时,foo
由 ADL 找到。因为现在 foo
正确地位于 C
的关联命名空间(全局命名空间)中。
但是它适用于内联匿名命名空间,即
inline namespace { }
因为 ADL 旨在与内联命名空间很好地配合使用。
我 long 自从停止将 static
用于辅助函数以支持匿名命名空间以来,它具有使用类型、变量和模板的优势以及功能。
但是,当我用包装器模板替换对它的调用时找不到函数时,我感到很惊讶。使用与我的项目匹配的编译器和选项查看 https://godbolt.org/z/GrojceqGx 处的代码。
#include <utility>
//#define WORKING
class C {};
template <typename Left, typename Right>
auto wrapper (Left&& left, Right&& right, const char* name)
{
return foo (std::forward<Left>(left),std::forward<Right>(right));
}
#ifdef WORKING
static
void foo (C& left, int right)
{
// compiles when using static function
}
#else
namespace {
void foo (C& left, int right)
{
// fails to compile in anonymous namespace
}
}
#endif
void sample()
{
C x;
wrapper (x, 17, "call 1");
}
为什么 wrapper
的实例化在 static
时看到 foo
而在匿名命名空间中却看不到?实例化点在这个翻译单元中,无论哪种方式都在同一个地方。
因为不管你信不信,匿名命名空间完全是另一个命名空间。而不是全局命名空间。
当您使用static
时,foo
由 ADL 找到。因为现在 foo
正确地位于 C
的关联命名空间(全局命名空间)中。
但是它适用于内联匿名命名空间,即
inline namespace { }
因为 ADL 旨在与内联命名空间很好地配合使用。