Определение признаков для шаблонных классов

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

class Traits
{
public:
    static bool someProperty(void) { return false; }
};

template<typename Type>
class MyTemplatisedClass
{
};

template<typename Type>
template<>
class Traits< MyTemplatisedClass<Type> >
{
public:
    static bool someProperty(void) { return true; }
};

int main(int argc, char* argv[])
{
    std::cout << Traits< MyTemplatisedClass<float> >::someProperty() <<std::endl; //This should be true
    return 0;
}

Это возможно или я слишком много прошу? Согласно компилятору, первая проблема

error C2989: 'Traits' : class template has already been declared as a non-class template    

Что правильно, но как это исправить? Если это имеет какое-то значение, мне не нужно, чтобы это работало для классов без шаблонов, достаточно только шаблонов. Редактировать: На самом деле было бы неплохо, если бы это работало для как шаблонные, так и не шаблонные классы.


person David Williams    schedule 22.12.2011    source источник


Ответы (3)


Traits должен быть шаблоном, чтобы быть специализированным.

В специализации отбросьте строку с пустым <>: это не шаблон, вложенный в шаблон или что-то в этом роде.

template <typename Type> //can only specialize templates
class Traits
{
public:
    static bool someProperty(void) { return false; }
};

template<typename Type>
class MyTemplatisedClass
{
};

template<typename Type>
//template<>  //Too much here
class Traits< MyTemplatisedClass<Type> >
{
public:
    static bool someProperty(void) { return true; }
};

Но если вы имели в виду специализацию для любого шаблона с одним аргументом типа, то это будет:

template < template <class> class SomeTemplatizedType, class Type>
//         ^^^^^^^^^^^^^^^^^^^^^^
//         names a template, not type
class Traits< SomeTemplatizedType<Type> >;
//            ^^^^^^^^^^^^^^^^^^^   ^
//             template name        |
//                               argument
person UncleBens    schedule 22.12.2011
comment
Спасибо, ребята, вы все дали правильный ответ, но я могу принять только один. Я собираюсь обратиться к UncleBens за дополнительной информацией. - person David Williams; 22.12.2011
comment
@UncleBens: Не могли бы вы привести примеры для обоих случаев. Я не совсем понимаю, в чем разница или что вы подразумеваете под специализацией любого шаблона с одним аргументом. - person Sarien; 27.08.2012

Исходный класс должен быть «базовым», то есть шаблонным, чтобы принимать любой аргумент типа. Затем вы можете беспокоиться о том, какие другие специализации вы хотели бы использовать.

template<typename T> class Traits
{
public:
    static bool someProperty(void) { return false; }
};

template<typename Type>
class MyTemplatisedClass
{
};

template<typename Type> class Traits< MyTemplatisedClass<Type> >
{
public:
    static bool someProperty(void) { return true; }
};

Чтобы на самом деле использовать это в вычислениях во время компиляции, вам нужно сделать его интегральным постоянным выражением ICE. Функция не может быть constexpr, даже если ее значение известно во время компиляции. В нынешнем виде я не могу сделать, например,

template<typename T> std::enable_if<Traits<T>::value, sometype> somefunc();
person Puppy    schedule 22.12.2011
comment
Спасибо, ребята, вы все дали правильный ответ, но я могу принять только один. Я собираюсь обратиться к UncleBens за дополнительной информацией. - person David Williams; 22.12.2011

Проблема в том, что вы объявили Traits как класс, а не шаблон класса. Просто добавьте template<typename> к определению Traits и удалите ложное template<> из специализации, и все будет в порядке.

template<typename>             // <--- Add this
class Traits
{
public:
    static bool someProperty(void) { return false; }
};

template<typename Type>
class MyTemplatisedClass
{
};

template<typename Type>
// template<>                 // <--- Remove this
class Traits< MyTemplatisedClass<Type> >
{
public:
    static bool someProperty(void) { return true; }
};

int main(int argc, char* argv[])
{
    std::cout << Traits< MyTemplatisedClass<float> >::someProperty() <<std::endl; //This should be true
    return 0;
}
person Mike Seymour    schedule 22.12.2011
comment
Спасибо, ребята, вы все дали правильный ответ, но я могу принять только один. Я собираюсь обратиться к UncleBens за дополнительной информацией. - person David Williams; 22.12.2011