4

Here are two overloading declarations of a function:

void fun(char& arg);
void fun(int&  arg);
void fun(long& arg);

The definitions are doing the same job:

void fun(char& arg) { ++arg; }
void fun(int&  arg) { ++arg; }
void fun(long& arg) { ++arg; }

How to declare and define the function once by using template, which accepts only int, char and long types for the argument? Error should appear as soon as possible (before runtime) if the function is misused (e.g. a variable of double type is passed).

Andy
  • 113
  • 2
  • 6

3 Answers3

4

You can just static_assert in the body of the function with a bunch of std::is_same

template<typename T>
void fun(T& arg) 
{ 
    static_assert(
        std::is_same_v<T, char> || 
        std::is_same_v<T, int> || 
        std::is_same_v<T, long>, 
        "bad call"); 
    ++arg; 
}
Caleth
  • 52,200
  • 2
  • 44
  • 75
  • I think I like this solution the best as you can actually provide a nice, readable error message, instead of the compilers very verbose error message. – NathanOliver Oct 16 '18 at 15:02
  • I like how I gave the same solution, at the exact same moment, but got -4 and no upvotes or edits because of a tangential, admittedly wrong statement :P Oh well, guess that's the way the cookie crumbles. – Lightness Races in Orbit Oct 16 '18 at 18:14
3

You can apply SFINAE with std::enable_if and std::is_same.

template <typename T>
std::enable_if_t<std::is_same_v<T, int> || 
                 std::is_same_v<T, char> || 
                 std::is_same_v<T, long>> 
fun(T& arg) { ++arg; }

For other types you'll get a no matching function for call error.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • 1
    This has the benefit that you can provide different overloads of `fun` for types other than `char&`, `int&` and `long&` elsewhere – Caleth Oct 16 '18 at 15:12
  • With return value: `template || std::is_same_v || std::is_same_v>* = nullptr> T fun(const T& arg) { return arg+1; }` – Andy May 15 '20 at 13:34
  • 1
    @Andy You can also `template std::enable_if_t || std::is_same_v || std::is_same_v, T> fun...`. – songyuanyao May 15 '20 at 14:08
0

In C++20, it can be implemented with constraints and concepts:

template <class T>
concept IsIntegral = is_same_v<T, char> 
                  || is_same_v<T,  int> 
                  || is_same_v<T, long>;

template <IsIntegral T>
void foo(T& arg) { ++arg; }

template <class T> requires IsIntegral<T>
void bar(T& arg) { ++arg; }
Andy
  • 113
  • 2
  • 6