C++ - перегрузить шаблонный метод класса с частичной спецификацией этого метода

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

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

Пример кода для подражания:

template <typename T, typename U>
class Test
{
public:
    void Set( T t, U u ); 

    T m_T;
    U m_U;
};

// Fully templated method that should be used most of the time
template <typename T, typename U>
inline void Test<T,U>::Set( T t, U u )
{
    m_T=t;
    m_U=u;
}

// Partial specialisation that should only be used when U is a float.
// This generates compile errors
template <typename T>
inline void Test<T,float>::Set( T t, float u )
{
    m_T=t;
    m_U=u+0.5f;
}


int _tmain(int argc, _TCHAR* argv[])
{
    Test<int, int> testOne;    
    int a = 1;
    testOne.Set( a, a );

    Test<int, float> testTwo;    
    float f = 1.f;
    testTwo.Set( a, f );
}

Я знаю, что могу написать частичную специализацию всего класса, но это отстой. Возможно ли что-то подобное?

(Я использую VS2008) Изменить: вот ошибка компиляции C2244: 'Test::Set': невозможно сопоставить определение функции с существующим объявлением

Спасибо :)


person JBeFat    schedule 05.03.2011    source источник


Ответы (3)


Конкретная проблема, которую вы рисуете, проста:

template< class T >
inline T foo( T const& v ) { return v; }

template<>
float foo( float const& v ) { return v+0.5; }

Затем вызовите foo из реализации Test::Set.

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

Ура и чт.,

person Cheers and hth. - Alf    schedule 05.03.2011

Вы не можете частично специализировать функцию-член, не определяя частичную специализацию самого шаблона класса. Обратите внимание, что частичная специализация шаблона ВСЕ ЕЩЕ является шаблоном, поэтому, когда компилятор видит Test<T, float>, он ожидает частичную специализацию шаблона класса.

--

В $ 14.5.4.3/1 из стандарта C++ (2003 г.) говорится:

Список параметров шаблона члена частичной специализации шаблона класса должен соответствовать списку параметров шаблона частичной специализации шаблона класса. Список аргументов шаблона члена частичной специализации шаблона класса должен соответствовать шаблону список аргументов частичной специализации шаблона класса. Специализация шаблона класса — это отдельный шаблон. Члены частичной специализации шаблона класса не связаны с членами первичного шаблона. Члены частичной специализации шаблона класса, которые используются способом, требующим определения, должны быть определены; определения членов первичного шаблона никогда не используются в качестве определений членов частичной специализации шаблона класса. Явная специализация члена частичной специализации шаблона класса объявляется так же, как явная специализация первичного шаблона.

Затем сам Стандарт дает этот пример,

// primary template
template<class T, int I> struct A {
void f();
};
template<class T, int I> void A<T,I>::f() { }

// class template partial specialization
template<class T> struct A<T,2> {
void f();
void g();
void h();
};
// member of class template partial specialization
template<class T> void A<T,2>::g() { }

Я надеюсь, что цитата из Стандарта вместе с примером хорошо ответит на ваш вопрос.

person Nawaz    schedule 05.03.2011

Есть еще одно решение проблемы частичной специализации, если вы не хотите вводить в свой код дополнительные функции, методы или классы.

#include <type_traits>

template <typename T1, typename T2>
class C
{
    void f(T1 t1);
}

template <typename T1, typename T2>
void C<T1, T2>::f(T1 t1)
{
    if (std::is_same<T2, float>::value)
    // Do sth
    else
    // Do sth
}
person Spook    schedule 02.01.2013