2009-11-12 5 views
60

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

template <class T> 
class TClass 
{ 
public: 
void doSomething(std::vector<T> * v); 
}; 

template <class T> 
void TClass<T>::doSomething(std::vector<T> * v) { 
// Do somtehing with a vector of a generic T 
} 

template <> 
inline void TClass<int>::doSomething(std::vector<int> * v) { 
// Do somtehing with a vector of int's 
} 

Но обратите внимание на встроенном в методе специализации. Требуется, чтобы код не имел ошибки компоновщика (в VS2008 есть LNK2005) из-за того, что метод определен более одного раза. Я понимаю это, потому что AFAIK полная спецификация шаблона совпадает с простым определением метода.

Итак, как я могу удалить это inline? Код не должен дублироваться при каждом его использовании. Я искал Google, прочитал некоторые вопросы здесь, в SO и попробовал многие из предлагаемых решений, но ни один из них не был успешно построен (по крайней мере, не в VS 2008).

Спасибо!

+3

Почему вы хотите удалить встроенную строку? Вы находите это эстетически неприятным? Считаете ли вы, что это изменяет смысл вашего кода? –

+0

Потому что, если этот метод будет «длинным» и использоваться во многих местах, я бы получил его двоичный код, скопированный везде, не так ли? Я попытался объяснить это в вопросе, но я думаю, что это было неясно ... :) – Chuim

+0

@Martin: Что, если для реализации требуется много другого кода, который затем должен быть включен этим заголовком вместо файла cpp? – sbi

ответ

50

Как и простые функции, вы можете использовать декларацию и реализацию. Положить в декларации заголовка:

template <> 
void TClass<int>::doSomething(std::vector<int> * v); 

и поставить реализацию в один из ваших CPP-файлов:

template <> 
void TClass<int>::doSomething(std::vector<int> * v) { 
// Do somtehing with a vector of int's 
} 

Не забудьте удалить инлайн (я забыл и думал, что это решение не будет работать:)). Проверено на VC++ 2005

+0

Я пробовал что-то по крайней мере похожее на это раньше, но у меня появились другие ошибки, но теперь, когда вы упомянули, я, должно быть, забыл удалить «inline» при копировании/вставке. Так оно и работало! – Chuim

+0

То же самое касается бесплатных шаблонов (в отличие от методов класса). Я получал ту же ошибку компоновщика для моей специализированной функции. Я переместил тело специализации функции в .cpp-файл и оставил объявление специализации в заголовке, и все сработало. Благодаря! – aldo

+0

Я просто столкнулся с этой проблемой, и выше это решило для меня. Кроме того, вам необходимо позаботиться о том, где компилятор * расширяет * код шаблона. Если это делается дважды, компилятор жалуется на несколько определений. – Diederik

3

Вам нужно перенести определение специализации в файл CPP. Специализация функции-члена класса шаблона допускается, даже если функция не объявлена ​​как шаблон.

+0

Это было то направление, о котором я уже знал. Но я искал окончательный ответ, потому что я не понял. – Chuim

1

Нет причин для удаления ключевого слова inline.
В любом случае это не изменяет смысл кода.

+0

Скопировано из вопроса комментариев: Потому что, если этот метод будет «длинным» и использоваться во многих местах, я бы получил его двоичный код, скопированный везде, не так ли? Я попытался объяснить это в вопросе, но, я думаю, это было неясно ... :) – Chuim

+0

№. Линкера удаляет любые дополнительные копии. Таким образом, в приложении или lib вы должны иметь только один экземпляр метода. –

+3

Если ключевое слово 'inline' приводит к тому, что функция фактически встроена (стандарт говорит, что компилятор должен воспринимать ее как подсказку), то эти дополнительные копии не могут быть удалены. Это, однако, только намек на inline (его основной эффект заключается в том, чтобы сказать «не генерировать ошибки при столкновении ссылок определенным образом») – Yakk

0

Если вы хотите удалить встроенную линию по какой-либо причине, решение maxim1000 совершенно допустимо.

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

Цитируя C++ FAQ

Есть несколько способов, чтобы указать, что функция является рядной, некоторые из , которые связаны с инлайн ключевым словом, а другие нет. Независимо от того, как вы назначьте функцию как встроенную, это запрос, чтобы компилятор разрешил игнорировать: компилятор мог бы встроить-расширить некоторые, все или ни одного мест, где вы вызываете функцию, обозначенную как встроенная. (Do not не рекомендуется, если это кажется безнадежно неопределенным. Гибкость выше на самом деле является огромным преимуществом: она позволяет компилятору обрабатывать большие функции по-разному, чем небольшие, плюс позволяет компилятору генерировать код, который легко debug, если вы выберете правильный компилятор .)

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

Смежные вопросы