重载分辨率,名称查找和函数指针

时间:2017-08-09 13:48:30

标签: c++ c++11 function-pointers overload-resolution argument-dependent-lookup

我遇到了查找和重载解析行为不同的情况:

  • 用于用户定义的类 vs 内置类型 vs std :: string
  • 用于直接调用 vs 函数指针调用

我无法确定标准的哪些确切部分证明了这些差异。

考虑以下C ++ 11代码:

#include <iostream>
#include <string>

using namespace std;

struct Test1 {};
struct Test2 {};

template<typename T>
int f(T t) { return 0; }

int f(Test1 t) { return 10; }
int f(int y) { return 20; }

template<typename T>
int use1() { return f(T()); }

template<typename T>
int use2() { auto fp = static_cast<int(*)(T)>(&f); return (*fp)(T()); }

int f(Test2 t) { return 30; }
int f(string s) { return 40; }
int f(double y) { return 50; }

int main() {
    cout << "use1<float>:  " << use1<float>()  << endl;
    cout << "use1<Test1>:  " << use1<Test1>()  << endl;
    cout << "use1<int>:    " << use1<int>()    << endl;
    cout << "use1<Test2>:  " << use1<Test2>()  << endl;
    cout << "use1<string>: " << use1<string>() << endl;
    cout << "use1<double>: " << use1<double>() << endl;
    cout << endl;
    cout << "use2<float>:  " << use2<float>()  << endl;
    cout << "use2<Test1>:  " << use2<Test1>()  << endl;
    cout << "use2<int>:    " << use2<int>()    << endl;
    cout << "use2<Test2>:  " << use2<Test2>()  << endl;
    cout << "use2<string>: " << use2<string>() << endl;
    cout << "use2<double>: " << use2<double>() << endl;
    return 0;
}

输出(与g ++ 6.3和clang ++ 5.0.0 trunk相同):

use1<float>:  0
use1<Test1>:  10
use1<int>:    20
use1<Test2>:  30
use1<string>: 0
use1<double>: 0

use2<float>:  0
use2<Test1>:  10
use2<int>:    20
use2<Test2>:  0
use2<string>: 0
use2<double>: 0

问题:

  1. 为什么use1<string>use1<Test2>不同?两种类型都声明为“在顶部”,两个f()重载都在底部声明。
  2. 为什么use1<Test2>use1<double>不同?相应的f()重载在相邻的行上,内置类型的处理有什么特别之处吗?
  3. 为什么use1<Test2>use2<Test2>不同? use2中函数指针的类型似乎与use1中的调用上下文匹配。

1 个答案:

答案 0 :(得分:0)

两阶段名称查找。在定义use1的位置,通过正常查找可以看到f的三个重载。在实例化时,可能会发现额外的重载 - 但只能通过依赖于参数的查找。 Test2位于全局命名空间中,因此ADL可以找到f(Test2);而string位于名称空间std中,因此ADL找不到f(string)(显然不在名称空间std中)。 double没有关联的命名空间,因此ADL根本没有启动。

use2中,f不是从属名称,因此根本不执行第二阶段查找 - 只考虑在定义点可见的重载。