Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible for a function to only accept a limited set of types for a given argument?

I know how to do it with any data type with template:

template<typename T>
T myFunc(T data) { ... }

But is there a way to narrow the set of allowed types to for example int and char or std::string and std::wstring, so the compiler would throw an error when encountering not allowed argument type and I will get error on compile time instead of run time ?

edit: Big thanks to ecatmur, now I understand the whole concept.

template<typename itemA_type, typename itemB_type>
typename std::enable_if<
  (
    std::is_same<itemA_type, int>::value ||
    std::is_same<itemA_type, char>::value) &&
  (
    std::is_same<itemB_type, std::string>::value ||
    std::is_same<itemB_type, std::wstring>::value ||
    std::is_same<itemB_type, const char*>::value ||
    std::is_same<itemB_type, const wchar_t*>::value
  ) ,
  void
>::type
myFunction(itemA_type itemA, itemB_type itemB) {
  using namespace std;
  cout << itemA << itemB << endl;
}
like image 451
rsk82 Avatar asked Jun 03 '14 15:06

rsk82


2 Answers

Take this utility trait class:

template<typename T, typename U, typename... Us>
struct is_any_of
    : std::integral_constant<
        bool,
        std::conditional<
            std::is_same<T,U>::value,
            std::true_type,
            is_any_of<T,Us...>
        >::type::value
      >
{ };

template<typename T, typename U>
struct is_any_of<T,U> : std::is_same<T,U>::type { };

Then you can use it in a static assertion:

template<typename T>
T myFunc(T data)
{
    static_assert( is_any_of<T, int, char, std::string>{}, "T not allowed");
}

You can use std::is_convertible or std::is_constructible instead of std::is_same if you feel it's more appropriate.

Live example.

like image 128
jrok Avatar answered Sep 20 '22 13:09

jrok


A simple solution using enable_if and is_same:

template<typename T>
typename std::enable_if<
    std::is_same<T, int>::value ||
    std::is_same<T, char>::value,
    T>::type
myFunc(T data) { ... }

As the predicate on T becomes more complex (for example, do you just allow string and wstring, or other specializations of basic_string?) you may start to want to write more complex predicate metafunctions; but for now, a simple expression is likely to suffice.

like image 41
ecatmur Avatar answered Sep 17 '22 13:09

ecatmur