【问题标题】:Overload resolution, name lookup and function pointers重载解析、名称查找和函数指针
【发布时间】:2017-08-09 13:48:30
【问题描述】:

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

  • 对于用户自定义类vs内置类型vsstd::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 主干相同):

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

【问题讨论】:

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


    【解决方案1】:

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

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

    【讨论】:

    • 谢谢!关于 use2:在 use2 中有没有办法获得一个函数指针,该指针包含在 use1 中解析的 f() 的完全相同的重载地址?
    • 我想不出任何方法来“依赖”一个名字。该标准仅设想在直接函数调用name(some_args) 中使用名称时的第二个查找阶段,而不是可能需要执行重载解析的其他情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多