Почему компилятор находит мою функцию, если она еще не объявлена? - программирование
Подтвердить что ты не робот

Почему компилятор находит мою функцию, если она еще не объявлена?

Вопреки моим ожиданиям, эта программа работает:

#include <iostream>


namespace a { struct item{}; }
namespace b { struct item{}; }


template<typename T>
void func(T t) { do_func(t); }


int main()
{    
    func(a::item{});
    func(b::item{});
}


namespace a { void do_func(item) { std::cout << "a::func\n"; } }
namespace b { void do_func(item) { std::cout << "b::func\n"; } }

Вывод:

a::func
b::func

Проверки с онлайн-компиляторами:

Если представление func<T> происходит в теле main, я бы ожидал, что a::do_func и b::do_func еще не объявлены.

Как это работает?

Update

Согласно @Marc Claesen, причина, по которой выше:

создается экземпляр шаблона после прочтения всего источника

Однако, почему этот код не работает:

#include <iostream>

template<typename T>
void func(T t) { do_func(t); }

int main()
{
    func(1);
}

void do_func(int) { std::cout << "do_func(int)\n"; }

Смотрите gcc-4.8:

error: 'do_func' was not declared in this scope,
and no declarations were found by argument-dependent
lookup at the point of instantiation [-fpermissive]

clang++ 3.4:

error: call to function 'do_func' that is neither
visible in the template definition nor found by
argument-dependent lookup

Итак, кажется, что комбинация шаблона функции и ADL необходимы, чтобы заставить ее работать.

Однако я не понимаю, почему это так.

4b9b3361

Ответ 1

Это работает из-за двух интересных вещей:

  • поиск двухфазных имен, который выполняется для зависимых от поиска имен.
  • и зависящий от аргумента поиск (ADL).

Посмотрите на это:

Короче говоря, do_func является зависимым именем, поэтому на первом этапе (когда файл обрабатывается только, но шаблон функции не создается) компилятор делает не разрешение имени do_func, он проверяет только синтаксис и видит, что это действительный вызов функции. Вот и все. Во второй фазе, когда экземпляр шаблона функции (и, следовательно, T известен), имя do_func разрешено, и в это время он также использует ADL для поиска имени.

Обратите внимание, что ADL работает только для пользовательских типов. Он не работает для встроенных типов, поэтому ваш второй код (т.е. func(1)) не работает!