2015-11-20 3 views
3

C++ Primer 5th Edition имеет фрагмент рекомендаций в конце главы 16.3 (глава обсуждения шаблона функции перегрузки):Декларирование шаблоны функций перед определением при перегрузке

Declare каждая функция перегрузки устанавливается, прежде чем определить любой из функций . Таким образом, вам не нужно беспокоиться о том, будет ли компилятор выполнить вызов, прежде чем он увидит функцию, которую вы намеревались вызывать.

Так это говорит мне, что при выборе кандидата и жизнеспособных функций при разрешении перегрузки возможно, что компилятор может создать шаблон функции, который не выбран в конце? Я пытался увидеть, может ли это на самом деле произошло:

template<class> struct always_false : std::false_type {}; 

template <typename T> void test(T const &){ 
    static_assert(always_false<T>::value, "If this fires, it is instantiated"); 
} 

template <typename T> void test(T*) { } 

int main(){ 
    int *q = nullptr; 
    test(q); //test(T*) should be the best match 
} 

Эта программа будет бросать ошибку компиляции, если test(T const &) был экземпляр в любой форме, за исключением того, программа компилируется нормально, как и ожидалось. Итак, какая ошибка компиляции - это тот наконечник, который пытается защитить меня? Когда это когда-нибудь создаст функцию, прежде чем она увидит функцию, которую я пытался вызвать?

+0

Связанные статьи по шаблону функции специализации и перегрузки: [? Почему не Специализируются шаблоны функций] (http://gotw.ca/publications/mill17.htm) – MicroVirus

ответ

5

Автор предупреждает вас об этом:

template<class> struct always_false : std::false_type {}; 

template <typename T> void test(T const &){ 
    static_assert(always_false<T>::value, "If this fires, it is instantiated"); 
} 

int main(){ 
    int *q = nullptr; 
    test(q); //test(T*) will not be matched. 
} 

template <typename T> void test(T*) 
{ 
} 

И это:

template<class> struct always_false : std::false_type {}; 

template <typename T> void test(T const &){ 
    static_assert(always_false<T>::value, "If this fires, it is instantiated"); 
} 

template <> void test<int>(int const &); 

void test(int *); 

int main(){ 
    int *q = nullptr; 
    test(q); //test(int*) should be the best match 
    int a; 
    test(a); // test<int>(int const&) should be the best match 
} 

template <> void test<int>(int const &) 
{ 
} 

void test(int *) 
{ 
} 

Если вы не предоставите заявления

template <> void test<int>(int const &); 

void test(int *); 

перед тем main, они выиграли» t соответствует main.

+0

_before он видит функцию, которую вы намереваетесь вызывать. _ «Before» - это то, что меня смущает, в примере, который вы предоставляете «test (T *)», никогда не было бы видно, был ли там «test (T const &)» или нет. Если это действительно то, что книга предлагает достаточно справедливо, но кажется, что это скорее урок о том, как держать вещи в сфере действия, чем что-либо, что связано с шаблонами. – AntiElephant

+0

@ AnthElephant, так как вы уже приняли мой ответ, я собираюсь предположить, что у вас есть ответы на ваши вопросы. –

2

Я видел много SO вопросов, некоторая вариация

template<class T, class... Ts> 
T sum(T t, Ts... ts) { return t + sum(ts...); } 
//^        | 
// |-------------------------------- 
// only one visible in 
//  definition context 

template<class T> 
T sum(T t) { return t; } 

int main() { 
    sum(1, 2); // doesn't compile 
} 

(типа возвращаемого значения не является совершенной, но вы получите идею.)

А потом люди удивляются, когда он не компилируется.

Или, даже больше удовольствия,

template<class T> void f(T t) { f((int)t); } 
void f(int) { /*...*/ } 

int main() { 
    f(1L); // infinite recursion 
} 
+0

За исключением случаев, когда 'T sum (T t)' найден ADL в момент создания экземпляра (не здесь), что делает его еще более забавным. Например, с 'struct Foo {Foo operator + (const Foo &) {return * this;}};' в глобальной области и вызывая 'sum (Foo {}, Foo {});' inside 'main()' будет компилироваться. – vsoftco

Смежные вопросы