简体   繁体   中英

Overload resolution, name lookup and function pointers

I have a case where lookup and overload resolution behaves differently:

  • for user-defined class vs built-in types vs std::string
  • for direct call vs function pointer call

I cannot figure what exact parts of the standard justify these differences.

Consider the following C++11 code:

#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;
}

Output is (same with g++ 6.3 and 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

Questions:

  1. Why use1<string> is different from use1<Test2> ? Both types are declared "at the top", both f() overloads are declared at the bottom.
  2. Why use1<Test2> is different from use1<double> ? Corresponding f() overloads are on adjacent lines, is there anything special in treatment of built-in types?
  3. Why use1<Test2> is different from use2<Test2> ? The type of a pointer to function in use2 seems to match the calling context in use1.

Two-phase name lookup. At the point where use1 is defined, three overloads of f are visible via normal lookup. At the point of instantiation, additional overloads may be found - but only by argument-dependent lookup. Test2 is in global namespace, so f(Test2) is found by ADL; whereas string is in namespace std , and so f(string) (which is, obviously, not in namespace std ) is not found by ADL. double has no associated namespaces, and so ADL doesn't kick in at all.

In use2 , f is not a dependent name, and so the second-phase lookup is not performed at all - only overloads visible at the point of definition are considered.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM