Явная специализация после создания

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

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 ответа

Решение

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

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

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

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

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

Другие вопросы по тегам