2015-01-04 2 views
4

Кодявная специализация не может быть другим заявлением

template <typename T> 
void foo(const T& t) 
{} 

template <typename T> 
class A 
{ 
    template <> 
    friend void foo<T>(const T& t) 
    {} 
}; 

дает компилировать ошибку

"defining explicit specialization ‘foo<T>’ in friend declaration friend void foo<T>(const T& t)" 

при компиляции с GCC и

"error C3637: 'A<int>::foo' : a friend function definition cannot be a specialization of a unction template" 

при компиляции в VS2013

Я подчинен d, что стандарт говорит так, но почему? Я хочу понять причину (под капотом) Существует много статей, в которых написано: «Явная специализация не может быть объявлением друга», но я не могу понять, почему. Есть идеи?

+1

gcc сообщает о явной специализации в области без пространства имен struct a ''и' template-id' foo 'в объявлении первичного шаблона' для заданного кода. – user2079303

+0

Извините, я скопирую пасту из другого источника –

+0

Явные специализации предотвращают неявное создание экземпляра. Каждый раз, когда вы создаете экземпляр 'A' для нового набора аргументов шаблона, вы должны добавить еще одну явную специализацию' foo'. Он плохо сформирован, не требует диагностики, чтобы добавить эту специализацию, если 'foo' уже был неявно создан для тех же аргументов шаблона [temp.expl.spec]/6. – dyp

ответ

3

Объявление явной специализации внутри шаблона класса для первого (и возможно только) времени означало бы, что явная специализация будет только «существующей» после создания экземпляра шаблона - независимо от того, зависит ли объявление от параметра шаблона или нет. Это создает множество проблем и может привести к нарушениям ОПР в различных сценариях, многие из которых, по-видимому, были бы плохо сформированными НДР; В основном из пункта упомянутой @dyp в комментариях, [temp.expl.spec]/6

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

Эти и другие причины делают такую ​​конструкцию слишком сложной, даже если она не очень полезна: то, что вы можете просто сделать, - это добавить специализацию как friend, никоим образом не указывая, была ли эта специализация создана или явно специализирована ,

friend void foo<T>(const T&); 

Любая явная специализация может быть добавлена ​​в область пространства имен.

+0

Или вы можете перегрузить, указав внутри себя функцию без шаблонов. – dyp

+0

Для полноты определения функции друга внутри класса обычно позволяет вызывать функцию без ADL, просто не используя объявление в классе.До тех пор, пока доступно объявление вне класса, это прекрасно, поэтому: 'struct S {friend void f() {}} void f(); int main() {f(); } 'отлично. Но для явных спецификаций шаблонов нужны те явные специализации, которые должны быть объявлены всякий раз, когда они используются, поэтому объявление в классе не будет достаточно хорошим. – hvd

+1

@Columbo Спасибо за ответ, но не могли бы вы более подробно объяснить дело ADL, я не понимаю проблему. Если специализация шаблона функции определена в классе, тогда он должен принять аргумент класса или класса, полученного из этого, поскольку механизм ADL должен работать. Итак, в чем проблема с определением специализации шаблона с таким (классным или производным) аргументом? –

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