C++名称解析困境

C++ name resolution woes

本文关键字:困境 C++      更新时间:2023-10-16

我有一个自定义类,我想提供sin函数的模板化版本 - 我已经在我的最小可验证重新定义中将其称为foo。由于其他地方的一些模板元编程,我的sin函数与普通sin函数具有相同的名称是有利的,因为它正在执行相同的工作,只是在不同的类型上。

但是,以下内容不会编译:

#include <cmath>
#include <iostream>
#include <cstdlib>
namespace test
{
template <std::size_t size>
class foo
{
};
template <std::size_t size>
void sin(const foo<size>& f)
{
}
template <class T>
void bar(const T& x)
{
using namespace ::std;
sin(x);
}
}
int main()
{
test::bar(0.5);
std::cout << "Done...";
std::getchar();
return EXIT_SUCCESS;
}

我收到以下编译器错误:

..testproblem.cpp(23,3): error: no matching function for call to 'sin'
sin(x);
^~~
..testproblem.cpp(29,8): note: in instantiation of function template specialization 'test::bar<double>' requested here
test::bar(0.5);
^
..testproblem.cpp(14,7): note: candidate template ignored: could not match 'foo<size>' against 'const double'
void sin(const foo<size>& f)
^
1 error generated.

我对此感到惊讶。有没有办法让bar编译而不使用模板元编程技巧来创建多个版本的bar

在 Clang 9 和 MSVC 2019 中失败。

using指令和 using 声明之间存在差异。using namespace ::std;是一个使用指令。就非限定名称查找而言,如果使用在名称查找点找不到名称,则 using 指令基本上只是转发名称查找以搜索命名空间::std到达包含两者的最近命名空间,包含指令的命名空间和指令 [namespace.udir]/2 指定的命名空间。在您的情况下,这意味着名称查找必须先到达全局命名空间,然后才能找到::std::sin。但是,名称查找将首先到达命名空间test,其中包含一个名为sin的函数,然后停止,因为它已经找到了它要查找的内容 [basic.lookup.unqual]/1。你想要的是一个 using 声明:

template <class T>
void bar(const T& x)
{
using std::sin;
sin(x);
}

与 using 指令相反,using 声明直接将声明的名称引入 using 声明所在的范围 [namespace.udecl]/1,这意味着将立即找到std::sin。现在,这意味着正常的非限定名称查找将不再在 using 声明后的块范围内找到test::sin。但是,由于依赖于参数的名称查找 [basic.lookup.argdep],如果test::foo的实例,将找到test::sin并再次设置部分重载T...

这是一个基于(a(评论和(b(评论中链接的答案的"快速修复"。bar函数的最小版本是:

void bar()
{
::sin(0.5); // Without "::" your templated "test::sin" hides the global namespace
// version - which is here referenced EXPLICITLY.
}