2017-02-14 3 views
3

Здесь я определить шаблон класса Foo, специализироваться своей функцией-члена, а затем поставить частичную специализацию для этого класса:то путает о шаблоне класса частичной специализации и член класса специализации

// this is Foo_0 
template<typename T, typename S> 
class Foo { 
public: 
    void operator()() { 
     std::cout << "Foo_0\n"; 
    } 
    template<typename R> 
    void bar(R) { 
     std::cout << "I'm from Foo_0\n"; 
    } 
}; 
template<> 
template<> 
void Foo<double, int>::bar(double) { 
    std::cout << "Now I'm specialized!\n"; 
} 

// this is Foo_1 
template<typename T> 
class Foo<T, int> { 
public: 
    void operator()() { 
     std::cout << "Foo_1\n"; 
    } 
}; 

И экземпляр Foo на VS2015 как это:

Удивительно, но F() печатает "Foo_0", что означает частичную специализированный шаблон Foo_1 не выбран. Что еще странно, когда я комментирую специализацию Foo :: bar (double), f() печатает «Foo_1»!

Тогда я проверить это:

Foo<int, int> f; 
f(); 

На этот раз, ф() также печатает "Foo_1", класс специализации применяется.

Таким образом, специализация элемента bar() влияет на применение частичной специализации шаблона класса. Это правда? Почему это работает так?

+0

Попробуйте переместить специализированную спецификацию шаблона функции ниже специализации шаблона частичного класса. –

+0

@Kerrek SB Когда я его перемещаю, компилятор жалуется, что «класс Foo не имеет панели элементов», кажется, что бар (double) считается членом Foo_1. – Dardai

+1

gcc успешно диагностирует проблему (в отличие от clang) [Demo] (http://coliru.stacked-crooked.com/a/ed9bb1a4e9682621). ('ошибка: частичная специализация 'class Foo ' после создания класса 'Foo ' [-fpermissive]') – Jarod42

ответ

3

Явная специализация Foo<double, int>::bar

template<> 
template<> 
void Foo<double, int>::bar(double) { 
    std::cout << "Now I'm specialized!\n"; 
} 

вызывает неявную экземпляра Foo<double, int>. Это лучше, чем частично специализированный Foo<T, int>, поэтому вы получите Foo_0 вместо Foo_1, если вы не указали специализацию bar.

Что вы можете сделать, это переместить bar(double) в шаблон общего класса Foo<T, S> как обычный перегруженной функции члена

template<class T, class S> 
class Foo { 
    // as before 

    void bar(double) { 
     std::cout << "Now I'm overloaded!\n"; 
    } 
}; 

Теперь вы получите Foo_1, live example. Обратите внимание, что вы не сможете позвонить по телефону Foo<double, int>::bar(double). Если вы этого хотите, то вам нужно добавить член bar к частичной специализации Foo<T, int>.

+1

Спасибо, это очень полезно – Dardai