2016-08-14 2 views
1

Можно ли специализировать функцию шаблона на enum?C++ specialize function on enum

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

Мой пример ниже показывает специализации для int, float и enum (он не компилируется, потому что он пытается перегрузить версию enum, а не специализирующийся его). Я чувствую, что мне не хватает чего-то очевидного.

Обратите внимание, что я ищу специализироваться на любой перечисление, а не только по имени один (EAnEnum в примере)

#include <iostream> 

enum class EAnEnum 
{ 
    Alpha, 
    Beta, 
}; 

template<typename T> 
void MyFunc(); 

template<> 
void MyFunc<int>() 
{ 
    std::cout << "Int" << std::endl; 
} 

template<> 
void MyFunc<float>() 
{ 
    std::cout << "Float" << std::endl; 
} 

// MyFunc<Enum> 
template<typename T> 
typename std::enable_if<std::is_enum<T>::value, void>::type MyFunc() 
{ 
    std::cout << "Enum" << std::endl; 
} 

int main() 
{ 
    MyFunc<EAnEnum>(); 
    return 0; 
} 
+0

Вы пытаетесь выполнить частичную специализацию шаблона функции. Нет такой вещи - вы можете заниматься полной специализацией или перегрузкой. Один из возможных подходов - перевести вашу специфичную для перечисления реализацию в первичный шаблон, возможно, с помощью 'static_assert', который на самом деле является перечислением. –

+1

Какую актуальную проблему вы пытаетесь решить. Нет, не этот вопрос, но проблема, на которую, по вашему мнению, ответ на этот вид специализации. –

+1

Специализация в целом не может быть лучшим способом решить практически любую проблему, которую вы пытаетесь решить с ней. Короче говоря, будет лучший способ. Решения становятся хрупкими и неудобными.Опишите настоящую проблему, решите ее по-другому. – Yakk

ответ

2

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

#include <iostream> 
#include<type_traits> 

enum class EAnEnum 
{ 
    Alpha, 
    Beta, 
}; 

template<typename> 
struct tag {}; 

void MyFunc(tag<int>) 
{ 
    std::cout << "Int" << std::endl; 
} 

void MyFunc(tag<float>) 
{ 
    std::cout << "Float" << std::endl; 
} 

void MyFunc(tag<EAnEnum>) 
{ 
    std::cout << "Enum" << std::endl; 
} 

template<typename T> 
void MyFunc() { 
    MyFunc(tag<std::decay_t<T>>{}); 
} 

int main() 
{ 
    MyFunc<EAnEnum>(); 
    return 0; 
} 

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

template<typename T> 
void MyFunc(tag<T>) 
{ 
    std::cout << "Fallback" << std::endl; 
} 

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

template<typename T> 
std::enable_if_t<std::is_enum<T>::value> 
MyFunc(tag<T>) 
{ 
    std::cout << "Fallback for enums only" << std::endl; 
} 

Обратите внимание, что вы не должны использовать непосредственно значения MyFunc, принимающие tag специализация в качестве точки входа.
Это означает, что внутренних функции.
Используйте вместо этого общий, как показано в примере.

+0

Разве это все еще не позволяет мне указывать имя моего перечисления явно, как в теге )? –

+0

@cz Для перегруженных функций теперь вы можете использовать _sfinae_ на своих «резервных» при необходимости. Позвольте мне изменить вопрос, чтобы прояснить этот момент. – skypjack

2

Вы не можете частично специализировать шаблон функции, но можете ли вы просто передать его шаблону класса.

Поскольку ваша функция не имеет аргументов, что это особенно легко:

#include <iostream> 
#include <type_traits> 

namespace impl { 
    using namespace std; 

    template< class Type, bool is_enum_ = is_enum<Type>::value > 
    struct Foo; 

    template< class Type > 
    struct Foo<Type, true> 
    { void func() { cout << "Enum" << endl; } }; 

    template<> 
    struct Foo<int> 
    { void func() { cout << "Int" << endl; } }; 

    template<> 
    struct Foo<float> 
    { void func() { cout << "Float" << endl; } }; 

} // namespace impl 

template< class Type > 
void foo() 
{ impl::Foo<Type>().func(); } 

auto main() 
    -> int 
{ 
    enum class An_enum 
    { 
     alpha, beta, 
    }; 

    foo<An_enum>(); 
    foo<int>(); 
    foo<float>(); 
    #ifdef TEST 
     foo<char>(); //! Doesn't compile. 
    #endif 
} 

С аргументами вы можете использовать “ ” идеальной переадресации (который не все, что совершенный, на самом деле, но, как правило, достаточно хорошо) с помощью std::forward ,