【问题标题】:Passing different types of parameters to a function template将不同类型的参数传递给函数模板
【发布时间】:2017-05-10 06:29:40
【问题描述】:

考虑这个模板:

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 等)取决于返回类型?

【问题讨论】:

  • 请注意,模板参数通常是大写的。

标签: c++ function templates


【解决方案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()。

但是,正如 cmets 中的 @Jarod42 所指出的,这只是一种观点,在某些情况下可能是错误的:例如,std::common_type&lt;char, char&gt;::typechar,而算术表达式 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::conditionalstd::is_same,在cmets中@Jarod42提出的更完整的解决方案允许以模板R作为第一个参数,并保持ab的自动推导:

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

【讨论】:

  • 该注释具有误导性,因为std::common_type_t&lt;char, char&gt;chardecltype('c' + 'c')int
  • 你甚至可以使用that 之类的方法将模板R 作为第一个参数并允许扣除T1T2
  • @Jarod42 thx,我正在寻找如何做到这一点。我编辑了我的答案
  • 使用特征是另一种可能的解决方案,它不需要额外的参数(无论如何它需要额外的类)。
【解决方案2】:

使用auto类型推导(c++14起):

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

【讨论】:

  • 请注意,char + char 的结果是 int,而其他答案的结果是 char
  • 对 C++11 的修改是将 auto add(t a, t b) 更改为 auto add(t a, t b) -&gt; decltype(a+b)
  • 如果@Jarod42 提到的行为不受欢迎,您可以提供专门化template&lt;&gt; auto add&lt;char, char&gt;(char a, char b) { return static_cast&lt;char&gt;(a + b); }(有或没有&lt;char, char&gt;,因为可以从参数列表中推断出tu )。但是请注意,这可能会导致数据丢失。
【解决方案3】:

在 c++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 类,它将真正开始大放异彩。


我更愿意保留标准强加的整体提升类型,所以也许这应该包含在另一个特征中。

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

can see 它会将 chars 添加到 int 中,就像标准促销规则一样。

【讨论】:

  • 请注意,对于 PiotrNycz 的回答,char + char 的结果为 int,而您的结果为 char
  • @Jarod42 - 有趣。使用我的模板时,这不会导致发出警告吗?添加仍然会导致int。但是返回类型是char
  • 我认为一些编译器有特殊的标志来检测隐式转换或可能的数据丢失。
  • @Jarod42 - 他们做到了。我只是不认为关闭这些是一个好主意。如果这段代码经常可以产生一个,也许还有改进的余地......
  • char有效的内容也对其他类型有效,如signed charshort intuint8_t、...(小于int的整数类型),所以你可以玩std::is_integralsizeof
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-25
  • 2018-01-02
  • 1970-01-01
  • 2011-08-26
  • 2012-10-27
相关资源
最近更新 更多