2016-05-13 1 views
4

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

template<typename T> void Func1(const T *in, T *out) 
{ 
    static_assert(std::is_same<T, INT8>::value 
        || std::is_same<T, UINT8>::value 
        || std::is_same<T, INT16>::value 
        || std::is_same<T, UINT16>::value, ""); 
    //... 
} 

template<typename T> void Func2(const T *in, T *out) 
{ 
    static_assert(std::is_same<T, INT32>::value || std::is_same<T, UINT32>::value, ""); 
    //... 
} 

template<typename T> void Func3(const T *in, T *out) 
{ 
    static_assert(std::is_same<T, float>::value || std::is_same<T, double>::value, ""); 
    //... 
} 

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

template<typename T> void Function(const T *in, T *out) 
{ 
    if (std::is_same<T, UINT8>::value 
     || std::is_same<T, UINT16>::value 
     || std::is_same<T, INT8>::value 
     || std::is_same<T, INT16>::value) 
    { 
     Func1(in, out); 
     return ; 
    } 

    if (std::is_same<T,INT32>::value || std::is_same<T,UINT32>::value) 
    { 
     Func2(in, out); 
     return ; 
    } 

    if (std::is_same<T,float>::value || std::is_same<T,float>:: double) 
    { 
     Func3(in, out); 
     return ; 
    } 
} 

Я считаю это решение абсолютно некрасиво, и я хотел бы знать, если что-то лучше/быстрее/более изящным возможно?

+2

Что такое 'беззнаковое float' и' беззнаковое double'? – WhiZTiM

+0

Можете ли вы использовать C++ 11? – Garf365

+0

@ Garf365: да! – FiReTiTi

ответ

5

Если вы используете C++ 11 или больше, вы можете использовать type_traits (SFINAE):

template<typename T> 
typename std::enable_if<std::is_same<T, INT8>::value 
      || std::is_same<T, UINT8>::value 
      || std::is_same<T, INT16>::value 
      || std::is_same<T, UINT16>::value>::type Function(const T*in, T*out) 
{ 
    Func1(in, out); 
} 

template<typename T> 
typename std::enable_if<std::is_same<T, INT32>::value 
      || std::is_same<T, UINT32>::value >::type Function(const T*in, T*out) 
{ 
    Func2(in, out); 
} 

template<typename T> 
typename std::enable_if<std::is_same<T, float>::value 
      || std::is_same<T, double>::value >::type Function(const T*in, T*out) 
{ 
    Func3(in, out); 
} 

Пример: http://coliru.stacked-crooked.com/a/b4f000fa6ffa8f19

Или, если вы не можете использовать C++ 11 или больше, вы можете использовать перегрузку вместо шаблона:

void Function(const UINT8 *int, UINT8 * out) 
{ 
    Func1(in, out); 
} 
... 
void Function(const UINT32 *int, UINT32 * out) 
{ 
    Func2(in, out); 
} 
... 

Или вы можете использовать template specialization, но в данном случае это не очень актуально (я оставляю его здесь, потому что это было в Origina l answer):

template<typename T> Function(const T *in, T *out); 

template<> void Function(const UINT8 *in, UINT8 * out) 
{ 
    Func1(in, out); 
} 

template<> void Function(const INT8 *in, INT8 * out) 
{ 
    Func1(in, out); 
} 

.... 
+1

И вместо специализации просто используйте перегрузку. Но предпочтительный подход для меня был бы SFINAE. – Jarod42

+0

@ Jarod42 Я добавляю его в ответ – Garf365

+0

Спасибо за ваш ответ. В вашем решении мне даже не нужно больше звонить Func *, я могу просто скопировать код внутри функции. Единственное, что не компилируется, это «:: type», но это происходит, если я удалю его. Почему это? (Я не забыл добавлять type_traits. – FiReTiTi

4

Вы можете написать черту, чтобы проверить, нет ли в списке тип. Эта версия использует std::disjunction из C++ 17, но вы можете просто скопировать-вставить реализацию из ссылки.

template <typename F, typename... T> 
using is_one_of = std::disjunction<std::is_same<F, T>...>; 

Затем используйте SFINAE с std::enable_if, чтобы выбрать перегрузки (std::enable_if_t является C++ 14, используйте typename std::enable_if<...>::type, если вы застряли 11).

template<typename T> 
std::enable_if_t<is_one_of<T, uint8_t, int8_t, uint16_t, int16_t>::value> 
Func(const T *in, T *out) 
{ 
    std::cout << "1\n"; 
} 

template<typename T> 
std::enable_if_t<is_one_of<T, uint32_t, int32_t>::value> 
Func(const T *in, T *out) 
{ 
    std::cout << "2\n"; 
} 

template<typename T> 
std::enable_if_t<std::is_floating_point<T>::value> 
Func(const T *in, T *out) 
{ 
    std::cout << "3\n"; 
} 

Обратите внимание, что вам даже не нужно Func1, Func2 и Func3, вы можете просто сделать различные Func перегрузок сделать вашу обработку.

Live Demo

+0

Спасибо за ваш ответ. Ошибка «is_one_of» генерирует ошибку. Я нашел «is_any_of» в google, но не «is_one_of». – FiReTiTi

+0

@FiReTiTi Какая ошибка? – TartanLlama

+0

Извините, я забыл об этом: Не удалось найти идентификатор «is_one_of». – FiReTiTi

Смежные вопросы