Явная специализация после создания - PullRequest
13 голосов
/ 15 октября 2011

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

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;
}

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

Ответы [ 2 ]

12 голосов
/ 15 октября 2011

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

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

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

3 голосов
/ 28 ноября 2012

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

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

...