Как работает разрешение перегрузки, когда аргумент является перегруженной функцией?
Разрешение перегрузки в C ++ может быть слишком сложным процессом. Требуется немало умственных усилий, чтобы понять все правила C ++, которые управляют разрешением перегрузки. Недавно мне пришло в голову, что наличие имени перегруженной функции в списке аргументов может усложнить разрешение перегрузки. Так как это был широко используемый случай, я отправилвопрос и получил ответ, который позволил мне лучше понять механику этого процесса. Однако формулировка этого вопроса в контексте iostreams, похоже, несколько отвлекла внимание от самой сути решаемой проблемы. Таким образом, я начал углубляться и нашел другие примеры, которые требуют более детального анализа проблемы. Этот вопрос является вводным и сопровождаетсяболее сложный.
ВопросПредположим, что каждый полностью понимает, как работает разрешение перегрузки при отсутствии аргументов, которые сами являются именами перегруженных функций. Какие изменения необходимо внести в их понимание разрешения перегрузки, чтобы оно также охватывало случаи, когда перегруженные функции используются в качестве аргументов?
ПримерыУчитывая эти заявления:
void foo(int) {}
void foo(double) {}
void foo(std::string) {}
template<class T> void foo(T* ) {}
struct A {
A(void (*)(int)) {}
};
void bar(int x, void (*f)(int)) {}
void bar(double x, void (*f)(double)) {}
void bar(std::string x, void (*f)(std::string)) {}
template<class T> void bar(T* x, void (*f)(T*)) {}
void bar(A x, void (*f2)(double)) {}
Приведенные ниже выражения приводят к следующему разрешению имениfoo
(хотя бы с gcc 5.4):
bar(1, foo); // foo(int)
// but if foo(int) is removed, foo(double) takes over
bar(1.0, foo); // foo(double)
// but if foo(double) is removed, foo(int) takes over
int i;
bar(&i, foo); // foo<int>(int*)
bar("abc", foo); // foo<const char>(const char*)
// but if foo<T>(T*) is removed, foo(std::string) takes over
bar(std::string("abc"), foo); // foo(std::string)
bar(foo, foo); // 1st argument is foo(int), 2nd one - foo(double)
Код для игры:#include <iostream>
#include <string>
#define PRINT_FUNC std::cout << "\t" << __PRETTY_FUNCTION__ << "\n";
void foo(int) { PRINT_FUNC; }
void foo(double) { PRINT_FUNC; }
void foo(std::string) { PRINT_FUNC; }
template<class T> void foo(T* ) { PRINT_FUNC; }
struct A { A(void (*f)(int)){ f(0); } };
void bar(int x, void (*f)(int) ) { f(x); }
void bar(double x, void (*f)(double) ) { f(x); }
void bar(std::string x, void (*f)(std::string)) { f(x); }
template<class T> void bar(T* x, void (*f)(T*)) { f(x); }
void bar(A, void (*f)(double)) { f(0); }
#define CHECK(X) std::cout << #X ":\n"; X; std::cout << "\n";
int main()
{
int i = 0;
CHECK( bar(i, foo) );
CHECK( bar(1.0, foo) );
CHECK( bar(1.0f, foo) );
CHECK( bar(&i, foo) );
CHECK( bar("abc", foo) );
CHECK( bar(std::string("abc"), foo) );
CHECK( bar(foo, foo) );
}