从以下内容开始(使用 gcc version 4.0.1
):
namespace name {
template <typename T>
void foo(const T& t) {
bar(t);
}
template <typename T>
void bar(const T& t) {
baz(t);
}
void baz(int) {
std::cout << "baz(int)\n";
}
}
如果我添加(在 global 命名空间中)
struct test {};
void bar(const test&) {
std::cout << "bar(const test&)\n";
}
然后,如我所料,
name::foo(test()); // produces "bar(const test&)"
但如果我只是添加
void bar(const double&) {
std::cout << "bar(const double&)\n";
}
它似乎找不到这个重载:
name::foo(5.0) // produces "baz(int)"
更重要的是,
typedef std::vector<int> Vec;
void bar(const Vec&) {
std::cout << "bar(const Vec&)\n";
}
也没有出现,所以
name::foo(Vec());
编译错误
error: cannot convert ‘const std::vector<int, std::allocator<int> >’ to ‘int’ for argument ‘1’ to ‘void name::baz(int)’
这就是查找的工作方式吗? (注意:如果我删除命名空间 name
,那么一切都会如我所料。)
如何修改此示例,以便考虑 bar
的任何重载? (我认为应该在 模板之前考虑重载?)
最佳答案
我假设您添加了 double
version 也添加到全局命名空间,然后调用 foo
在定义完所有内容后从 main 开始。所以这基本上是两个阶段的名称查找。查找因调用中的参数依赖(取决于其类型)而依赖的非限定函数名称分两个阶段完成。
第一阶段在定义上下文中进行非限定和参数相关的查找。然后它卡住结果,并使用实例化上下文(实例化点的声明的总和)仅进行第二个参数依赖查找。 No 不再进行不合格查找。因此,对于您的示例,它意味着:
来电
bar(t)
在foo<test>
内查找bar
在实例化上下文中使用参数相关查找(它不会使用非限定查找找到它,因为foo
被声明为above
栏模板)。取决于你是否定义全局bar
在foo
之前或之后模板,它将找到全局bar
在第一阶段已经使用参数依赖查找的声明(它在test
的命名空间中定义)。然后 main 中的调用将实例化foo<test>
并且有可能找到bar
在这个阶段(如果你在声明模板之后声明它)。来电
bar(t)
在foo<int>
内不进行参数相关的查找(或者更确切地说,查找的结果是一个空的声明集),因为int
是一个基本类型。因此,在定义上下文中的非限定查找也将一无所获,因为匹配bar
模板已声明after
foo
模板。该调用格式错误,标准在14.6.4.2/1
说明了这种情况。If the call would be ill-formed [...] then the program has undefined behavior.
因此,您应该将此视为“我做了一件肮脏的事情,编译器选择不打我”的情况,我认为:)
来电
bar(t)
在foo<Vec>
内将再次进行查找,并将在std::
中查找 bar (因为那是定义std::vector
的地方)。它没有找到bar
在那里,既不在定义上下文中。所以它决定再次使用未定义的行为,并使用bar
模板,并且它本身通过使用baz
再次执行未定义的行为在它之后声明,ADL 或定义上下文中的非限定查找都找不到。如果 vector 是
vector<test>
, 然后查找bar
也会在全局范围内完成,因为依赖于参数的查找不仅会直接使用参数类型,还会使用其中的模板参数类型(如果有的话)。
如果您使用 GCC,那么不要完全依赖它的行为。在下面的代码中,它声称调用不明确,尽管代码非常好 - f
在 afake
不应该是候选人。
namespace aname {
struct A { };
void f(A) { }
}
namespace afake {
template<typename T>
void g(T t) { f(t); }
void f(aname::A) { }
}
int main() { aname::A a; afake::g(a); }
如果你想测试你的代码片段的一致性,最好使用 comeau online compiler与严格的设置。
关于c++ - 将函数查找与 C++ 中的模板混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1396458/