Undefined эталонная ошибка для метода шаблона

Это сводило меня с ума за последние полтора часа. Я знаю это маленькую вещь, но не могу найти то, что неправильно (факт, что он дождливый день в пятницу, конечно, не помогает).

Я определил следующий класс, который будет содержать параметры конфигурации, считанные из файла, и предоставит мне доступ к ним из моей программы:

class VAConfig {
    friend std::ostream& operator<<( std::ostream& lhs, const VAConfig& rhs);

private:
    VAConfig();
    static std::string      configFilename;
    static VAConfig*        pConfigInstance;
    static TiXmlDocument*   pXmlDoc;
    std::map<std::string, std::string> valueHash;

public:
    static VAConfig* getInstance();
    static void setConfigFileName( std::string& filename ) { configFilename = filename; }
    virtual ~VAConfig();

    void readParameterSet( std::string parameterGroupName );
    template<typename T> T readParameter( const std::string parameterName );
    template<typename T> T convert( const std::string& value );
};

где метод convert() определяется в VAConfig.cpp как

template <typename T>
T VAConfig::convert( const std::string& value )
{
    T t;
    std::istringstream iss( value, std::istringstream::in );
    iss >> t;
    return t;
}

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

int y = parameters->convert<int>("5");

Я получаю ошибку компиляции undefined reference to 'int VAConfig::convert<int>...'. То же самое для readParameter().

Посмотрел на множество шаблонов, но coul не понял этого. Любые идеи?

Ответ 1

Реализация внедренного кода никогда не должна быть в файле .cpp: ваш компилятор должен видеть их одновременно с тем, что видит код, который их вызывает (если вы не используете явный экземпляр для генерации шаблонного объектного кода, но даже тогда .cpp используется не тот тип файла).

Что вам нужно сделать, это переместить реализацию в файл заголовка или в файл, например VAConfig.t.hpp, а затем #include "VAConfig.t.hpp" всякий раз, когда вы используете любые шаблонные функции-члены.

Ответ 2

Если вы переместите реализацию шаблонных методов (convert and readParameter) в файл заголовка, он должен работать.

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

Ответ 3

Метод шаблона - это просто... шаблон для метода. Аргументы шаблона должны быть заполнены, когда метод "создан".

Должно быть возможно создать компилятор, который содержит объявление метода шаблона, а также шаг "компиляция шаблона", скомпилировать все необходимые экземпляры метода шаблона.

Это не относится к microsoft vc. Я слышал, что коллеги бормотали об этом в случае с Unix.

Большинство компиляторов создают экземпляр метода шаблона по запросу, где они используются в исходном коде. Чтобы создать экземпляр метода, компилятор должен "видеть" тело функции шаблона. Именно поэтому тело чаще всего помещают либо в заголовочный файл, либо, например, в файл .h.cpp, который затем включается как последняя строка файла .h.