Передача различных типов параметров в шаблон функции

Рассмотрим этот шаблон:

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

Как передать различные типы параметров, чтобы возвращаемое значение было:

  • int, если оба параметра имеют тип int.

  • float, если один из параметров имеет тип float.

  • float, если оба параметра имеют тип float.

Я также пробовал иметь несколько параметров для шаблона:

template<typename t, typename c>

используя их для параметров функции, чтобы они могли быть разными (t add(t a, c b)), но то, что я не могу обернуть вокруг, - это как изменить тип функции (int, float, double и т.д.) в зависимости от тип возврата?

Ответ 1

Вы хотите std::common_type:

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

В документации указано:

Для арифметических типов общий тип может рассматриваться как тип (возможно смешанного) арифметического выражения, такого как T0() + T1() +... + Tn().

Но, как указано в комментариях @Jarod42, это просто представление и может быть ошибочным в некоторых случаях: например, std::common_type<char, char>::type есть char, тогда как арифметическое выражение char() + char() дает int.


Более полная реализация может явно привести результат для удаления возможных предупреждений в приведенных выше случаях:

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);
}

Здесь std::common_type используется по умолчанию для типа возвращаемого значения, но поскольку он является параметром шаблона, вы можете указать другой тип при использовании функции (может быть полезен в более сложных случаях использования):

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

Использование std::conditional и std::is_same, еще более полное решение, предложенное @Jarod42 в комментариях, позволяет иметь шаблон R в качестве первого параметра и сохранять автоматический вывод для a и 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);
}

Использование:

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

Ответ 2

Используйте auto вывод типа (С++ 14):

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

Ответ 3

В С++ 11 и далее вы можете использовать std::common_type

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

Он будет работать так, как будто происходят целые рекламные акции, не сильно отличающиеся от того, как делать вывод типа auto, как в ответе Piotr. Но он действительно начнет светиться, если вы попытаетесь передать пользовательские типы в качестве параметров, например std::complex classes.


Я бы предпочел сохранить целые типы поощрений, которые накладывает стандарт, поэтому, возможно, это должно быть обернуто другим признаком.

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;
}

Вы можете видеть, он добавляет char в int, как это делают стандартные правила продвижения.