Специализация члена шаблона класса шаблона - PullRequest
2 голосов
/ 24 февраля 2012

У меня есть структура класса,

template<int T>
class MyClass {
public:
    MyClass(){};
    ~MyClass(){};

    template<class K> void foo();
};

Теперь я хочу специализировать метод foo() на основе значения целого числа, используемого в MyClass<int>, например, если int в коде, который мы имеемMyClass<2> Я хочу использовать другую версию foo<K>(), если бы у меня был MyClass<3>.Тем не менее, я хочу иметь foo<K>() неспециализированных на K.

Так что это будет означать что-то вроде этого будет хорошо

MyClass<2> myc2;
MyClass<3> myc3;
myc2.foo<SomeClass>();
myc2.foo<SomeOtherClass>();
myc3.foo<SomeClass>();
myc3.foo<SomeOtherClass>();

Можно ли специализироваться таким образом, но неспециализируешься на K?Я попробовал несколько комбинаций безуспешно.

Ответы [ 5 ]

2 голосов
/ 24 февраля 2012

Если я правильно понял ваш вопрос, это то, что вы хотите:

template<int T>
class MyClass {
public:
    MyClass(){};
    ~MyClass(){};

    template<class K> void foo();
};

template<int T>
template<class K>
void MyClass<T>::foo()
{
    std::cout << "general form\n";
}

template<>
template<class K>
void MyClass<2>::foo()
{
    std::cout << "MyClass<2>\n";
}

int main()
{
    MyClass<3> c1;
    c1.foo<int>(); // general form
    MyClass<2> c2;
    c2.foo<int>(); // MyClass<2>
    c2.foo<float>(); // MyClass<2>
}
1 голос
/ 24 февраля 2012

Это работает под моим Visual C ++ 2010:

template<int T>
class MyClass {
public:
    MyClass(){};
    ~MyClass(){};
    template<class K> void foo() {
        std::cout << "foo() for T" << std::endl;
    }
};

template<>
template<class K>
void MyClass<2>::foo() {
    std::cout << "foo() for 2" << std::endl;
}

template<>
template<class K>
void MyClass<3>::foo() {
    std::cout << "foo() for 3" << std::endl;
}

void main() {
    MyClass<1>().foo<int>();
    MyClass<2>().foo<float>();
    MyClass<3>().foo<std::string>();
}

Это печатает:

foo() for T
foo() for 2
foo() for 3
1 голос
/ 24 февраля 2012

Вы можете попробовать boost :: enable_if, он позволяет включать или отключать определенные специализации классов и методов. Взгляните на примеры здесь: http://www.boost.org/doc/libs/1_48_0/libs/utility/enable_if.html

0 голосов
/ 24 февраля 2012

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

#include <iostream>

template<int T>
class MyClass {
public:
    MyClass(){};
    ~MyClass(){};

    class fooImpl;

    template<class K> void foo()
    {
       fooImpl::fn<K>();
    }
};

template<>
class MyClass<2>::fooImpl
{
public:
   template <class K> static void fn()
   {
      std::cout << "two : " << typeid(K).name() << "\n";
   }
};

template<>
class MyClass<3>::fooImpl
{
public:
   template <class K> static void fn()
   {
      std::cout << "three : " << typeid(K).name() << "\n";
   }
};

class SomeClass {};
class SomeOtherClass {};

int main()
{
   MyClass<2> myc2;
   MyClass<3> myc3;
   myc2.foo<SomeClass>();
   myc2.foo<SomeOtherClass>();
   myc3.foo<SomeClass>();
   myc3.foo<SomeOtherClass>();

   return 0;
}

Тогда вам нужно только специализировать классы реализации foo (fooImpl), а не все другие функции-члены в MyClass, которые вы можете добавить.

Мой компилятор выдал следующий вывод:

two : class SomeClass
two : class SomeOtherClass
three : class SomeClass
three : class SomeOtherClass
0 голосов
/ 24 февраля 2012

Не специализируйся.Просто делегируйте вызов перегруженной функции как:

template<int T>
class MyClass {
public:
    MyClass(){};
    ~MyClass(){};

    template<class K> 
    void foo()
    {
      foo_worker(static_cast<K*>(0)); //delegate to overloaded function
    }
private:
    template<class K>
    void foo_worker(K*)
    {
        //general code goes here
    } 
    void foo_worker(SomeClass*)
    {
        //code when K = SomeClass
    } 
    void foo_worker(SomeOtherClass*)
    {
        //code when K = SomeOtherClass
    } 
};

И вот как это будет работать:

  • Если K равно SomeClass, тогда foo_worker(SomeClass*) будетв конечном итоге будет вызван.
  • Иначе, если K будет SomeOtherClass, тогда будет вызван foo_worker(SomeOtherClass*).
  • В противном случае будет вызван общий foo_worker.1020 * Обратите внимание, что параметр в foo_worker используется, чтобы позволить компилятору выбрать правильную перегруженную функцию.
...