блокировать функцию, когда тип аргумента не принадлежит набору типов

#c #c 17 #sfinae #typetraits

#c #c 17 #sfinae #typetraits

Вопрос:

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

Поэтому я попытался использовать уже доступный std::type_traits , а затем использовать std::enable_if для блокировки создания экземпляра. Вот моя реализация.

 // C  17
#include <vector>
#include <cstdint>
#include <iostream>
#include <type_traits>

using my_int_t      = std::int16_t;         // T1
using my_string_t   = std::string;          // T2
using my_vec_t      = std::vector<int>;     // T3
// and so on .. a long list of types 


/* Check input Type T : if it belongs to {T1,T2,T3} 
If it belongs then only allow this version of func to instantiate
*/
template<typename T, typename T1,typename T2,typename T3>
using isCompatible = std::bool_constant<std::is_same_v<T,T1>
                            || std::is_same_v<T,T2>
                            || std::is_same_v<T,T3> >;

template<typename T>
using CompatibleTypeCheck = std::enable_if_t< isCompatible<std::remove_reference_t<T>,
                                                    my_int_t,
                                                    my_string_t,
                                                    my_vec_t>::value >;



template<typename T,
        typename = CompatibleTypeCheck<T>>
void func(Tamp;amp; val) {
    std::cout <<"Hello from Generic Func" << std::endl;
}


int main() {

    // int z = 10;   
    // func(z); // Error ! as expected

    my_int_t w = 100;
    func(w); // OK
}
  

Но проблема в том, что слишком много разрешенных типов. Есть ли лучший способ очистить оба шаблона псевдонимов? т.е. isCompatible и CompatibleTypeCheck .

Если есть какой-либо лучший «идиоматический» способ достижения того же результата, пожалуйста, предложите его.

Ответ №1:

Вы можете написать isCompatible так:

 template<typename T, typename ...Ts> 
using isCompatible = std::bool_constant<(std::is_same_v<T,Ts> || ...)>;
  

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

Вот демонстрация.


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

 template<typename T>
void func(Tamp;amp; val) {
    static_assert(isCompatible<std::remove_reference_t<T>,
                                                    my_int_t,
                                                    my_string_t,
                                                    my_vec_t>::value);
    std::cout <<"Hello from Generic Func" << std::endl;
}
  

что позволяет полностью избежать необходимости CompatibleTypeCheck .

Вот демонстрация.