Я думал, что будет вызвана перегрузка функции с наиболее конкретными совпадающими типами аргументов, но, похоже, я не понимаю аспект вывода типов, когда шаблон и наследуемые типы объединяются.
Пример:
#include<iostream>
#include<typeinfo>
struct Foo {};
struct Bar : Foo {};
#ifdef FOO
void print_typeid( const Foo& f ) {
std::cout << "(F) typeid: " << typeid(f).name() << std::endl;
}
#endif // FOO
#ifdef GENERIC
template<typename Generic>
void print_typeid( const Generic& g ) {
std::cout << "(G) typeid: " << typeid(g).name() << std::endl;
}
#endif // GENERIC
int main( int argc, char *argv[] ) {
Foo foo; print_typeid(foo);
Bar bar; print_typeid(bar);
return 0;
}
Контрольные примеры
1.Определить только FOO
$ g++ -DFOO main.cpp -o foo && ./foo
Вывод:
(F) typeid: 3Foo
(F) typeid: 3Foo
Это имеет смысл для меня, поскольку объекты foo
и bar
могут быть переданыкак const Foo&
, и поскольку во время компиляции нет понижения, bar
должен быть идентифицирован как имеющий тип Foo
.
2.Определить только GENERIC
$ g++ -DGENERIC main.cpp -o generic && ./generic
Вывод:
(G) typeid: 3Foo
(G) typeid: 3Bar
Это также имеет смысл, так как foo
и bar
являются lvalues и могут бытьпередается в функцию, которая принимает общую константную ссылку.Это печатает фактический тип каждого объекта.
3.Определите FOO и GENERIC
$ g++ -DFOO -DGENERIC main.cpp -o both && ./both
Вывод:
(F) typeid: 3Foo
(G) typeid: 3Bar
Это меня смущает.Уже установив, что оба объекта могут быть переданы обеим функциям, я ожидал, что, поскольку const Foo&
является более конкретным совместимым типом для bar
, мы получили бы тот же вывод, что и в случае 1. Почему это происходит?
Протестировано с использованием gcc 7.2 и clang 4