简体   繁体   中英

Passing different types of parameters to a function template

Consider this template:

template<typename t>
t add(t a, t b) {
    return a+b;
}

How can I pass different types of parameters so the return value will be:

  • int if both parameters are of type int .

  • float if one of the parameters is of type float .

  • float if both parameters are of type float .

I've also tried having multiple parameters for the template:

template<typename t, typename c>

using them for the function parameters so they can be different ( t add(ta, cb) ) but what I can't wrap my head around is how can I change the type of function (int, float, double, etc.) depending on the return type?

Use auto type deduction (since c++14):

template<typename t, typename u>
    auto add(t a, u b) {
        return a+b;
    }

What you want is std::common_type :

template<typename T0, typename T1>
typename std::common_type<T0, T1>::type add(T0 a, T1 b) {
    return a+b;
}

The documentation states:

For arithmetic types, the common type may be viewed as the type of the (possibly mixed-mode) arithmetic expression such as T0() + T1() + ... + Tn().

But, as pointed by @Jarod42 in the comments, this is just a view, and may be wrong in some cases: for example, std::common_type<char, char>::type is char whereas the arithmetic expression char() + char() yields int .


A more complete implementation may explicitly cast the result to remove possible warnings in the cases cited above:

template<typename T0, typename T1, typename R = std::common_type_t<T0, T1>>
R add(T0 a, T1 b) {
    return static_cast<R>(a+b);
}

Here std::common_type is used by default for return type, but since it is a template parameter, you may specify a different type when using the function (may be useful in more complex use cases):

char a = 1, b = 2;
add<decltype(a), decltype(b), int>(a, b);

Using std::conditional and std::is_same , an even more complete solution proposed by @Jarod42 in the comments allows to have template R as first parameter, and keep automatic deduction for a and b :

template <typename R, typename T0, typename T1>
using ResType = std::conditional_t<
    std::is_same<void, R>::value,
    std::common_type_t<T0, T1>, // default
    R                           // R was explicitly specified: use it
>;

template <typename R = void, typename T0, typename T1>
ResType<R, T0, T1> add(T0 a, T1 b)
{
    return static_cast<ResType<R, T0, T1>>(a + b);
}

Usage:

char a = 1, b = 2;
add(a, b);       // returns char
add<int>(a, b);  // returns int

In c++11 and onward, you can use std::common_type

template<typename T1, typename T2>
auto add(T1 a, T2 b) -> typename std::common_type<T1, T2>::type {
  return a + b;
}

It will work as if integral promotions are happening, not much different than just doing auto type deduction, as in Piotr 's answer. But it will really start to shine if you try to pass custom types as parameters, such as std::complex classes.


I'd prefer to preserve the integral promotion types that the standard imposes, so perhaps this should be wrapped in another trait.

template<typename T1, typename T2>
class AdditionTraits {
  using common_t = typename std::common_type<T1, T2>::type;
  constexpr static bool is_char = std::is_same<common_t, char>::value;
public:
  using type = typename std::conditional<is_char, int, common_t>::type;
};

template<typename T1, typename T2>
auto add(T1 a, T2 b) -> typename AdditionTraits <T1, T2>::type {
  return a + b;
}

You can see it adds char s into an int , as the standard promotion rules do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM