Подтвердить что ты не робот

Явная специализация после создания экземпляра

У меня есть следующий код:

typedef vector<int> Vec;
typedef vector<Vec> VecOfVec;

template<typename Vec>
Vec DoSomething(const Vec &v);

template<>
VecOfVec DoSomething<VecOfVec>(const VecOfVec &v)
{
    VecOfVec r;
    for(auto i = v.begin(); i != v.end(); i++)
        r.push_back(DoSomething(*i));
    return r;
}

template<>
Vec DoSomething<Vec>(const Vec &v) // Error here
{
    return v; // for the sake of the example
}

Я получаю следующую ошибку:

explicit specialization of 'DoSomething<vector<int> >' after instantiation

на отмеченной строке.
Компилятор утверждает, что он уже создавал экземпляр DoSomething<vector<int> >, хотя он не может, и простая программа может это доказать:

typedef vector<int> Vec;
typedef vector<Vec> VecOfVec;

template<typename Vec>
Vec DoSomething(const Vec &v);

template<>
VecOfVec DoSomething<VecOfVec>(const VecOfVec &v)
{
    VecOfVec r;
    for(auto i = v.begin(); i != v.end(); i++)
        r.push_back(DoSomething(*i));
    return r;
}

Результаты неразрешенного внешнего.
Почему компилятор говорит, что он уже создавал его, когда он не может и даже не делает этого? и почему компилятор не рассматривает его как неразрешенный символ, а компоновщик делает? Я знаю, что переключение метода метода решает его, но я хочу знать, почему компилятор делает это.

4b9b3361

Ответ 1

Код запросил неявное создание экземпляра в DoSomething(*i). Тот факт, что вы не определили шаблон в этой единице перевода, означает, что он не может создать экземпляр специализации, поэтому DoSomething(*i) дает в вашем случае ошибку "неразрешенный символ" (linker-). Чтобы избавиться от этой ошибки, вам нужно либо определить шаблон в этом TU, либо предоставить явную директиву о создании этого шаблона в TU, где вы определяете шаблон.

Сам факт того, что код запросил неявное создание для специализации DoSomething<vector<int> >, прежде чем вы явно указали, что специализации достаточно, чтобы программа стала плохо сформированной (без необходимости диагностики, хотя, компилятор делает хорошую работу здесь, что это не требуется).

Как замечает @CharlesBailey, объявление полной специализации вполне достаточно; его определение может быть дано в другом месте, даже вне использования TU.

Ответ 2

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

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