Jes*_*der 3 c++ lookup templates
从以下开始(使用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";
}
}
Run Code Online (Sandbox Code Playgroud)
如果我添加(在全局命名空间中)
struct test {};
void bar(const test&) {
std::cout << "bar(const test&)\n";
}
Run Code Online (Sandbox Code Playgroud)
然后,正如我所料,
name::foo(test()); // produces "bar(const test&)"
Run Code Online (Sandbox Code Playgroud)
但是,如果我只是添加
void bar(const double&) {
std::cout << "bar(const double&)\n";
}
Run Code Online (Sandbox Code Playgroud)
它似乎无法找到这个重载:
name::foo(5.0) // produces "baz(int)"
Run Code Online (Sandbox Code Playgroud)
更重要的是,
typedef std::vector<int> Vec;
void bar(const Vec&) {
std::cout << "bar(const Vec&)\n";
}
Run Code Online (Sandbox Code Playgroud)
也没出现
name::foo(Vec());
Run Code Online (Sandbox Code Playgroud)
给出编译器错误
error: cannot convert ‘const std::vector<int, std::allocator<int> >’ to ‘int’ for argument ‘1’ to ‘void name::baz(int)’
Run Code Online (Sandbox Code Playgroud)
这是查找应该如何工作?(注意:如果删除命名空间name,那么一切都按预期工作.)
如何修改此示例以便考虑任何重载bar?(我认为重载应该在模板之前考虑?)
我假设您也将double版本添加到全局命名空间,并foo在定义完所有内容后从main 调用.所以这基本上是两阶段名称查找.查找依赖的非限定函数名,因为调用中的参数依赖于(在其类型上)两个阶段.
第一阶段在定义上下文中执行非限定和参数依赖的查找.然后它冻结的结果,以及使用该实例化上下文(声明中的实例化点之和)做了第二个参数依赖查找只.不再进行不合格的查找.所以对于你的例子,它意味着:
通话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
如果调用不正确[...]则程序具有未定义的行为.
你应该认为这是"我做了一件肮脏的事情,编译器选择不打我"的情况,我认为:)
bar(t)内部调用foo<Vec>将再次执行查找,并将查找bar std::(因为这std::vector是定义的位置).它bar在定义上下文中都没有找到它.因此它决定再次使用未定义的行为,并使用bar模板,并且它本身再次通过使用在其baz之后声明的未定义行为,并且ADL既不能找到也不能从定义上下文中找到非限定查找.
如果向量是a vector<test>,那么查找bar也将在全局范围内完成,因为依赖于参数的查找不仅会直接使用参数类型,还会使用它们中的模板参数的类型(如果有的话).
如果您使用GCC,那么不要完全依赖它的行为.在下面的代码中,它声称调用是模糊的,虽然代码非常好 - fin 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); }
Run Code Online (Sandbox Code Playgroud)
如果您想针对一致性测试您的代码段,最好使用具有严格设置的comeau在线编译器.