为什么在调用模板化函数时不考虑参数转换?

时间:2017-12-04 15:06:47

标签: c++ templates

我有一个模板类和一个朋友operator*函数

StereoSmp<TE> operator* (const StereoSmp<TE>& a, TE b)

我将其与TE=float一起使用,但我需要乘以StereoSmp<float> * double 我认为这应该是可能的,因为它应该自动将double转换为float并且有效但我得到错误:

no match for ‘operator*’ (operand types are ‘StereoSmp<float>’ and
    ‘__gnu_cxx::__alloc_traits<std::allocator<double> >::value_type {aka double}’) 
deduced conflicting types for parameter ‘TE’ (‘float’ and ‘double’)

为什么它不会自动将double转换为float?我该怎么做才能允许类型之间的自动转换?

4 个答案:

答案 0 :(得分:5)

不要让你的朋友成为模板。

template<class TE>
struct StereoSmp {
  friend StereoSmp operator* (const StereoSmp& a, TE b) {
    return multiply( a, b ); // implement here
  }
};

这是模板StereoSmp的每个类型实例的非模板朋友。它会考虑转换。

模板功能不考虑转换,它们只是进行精确的模式匹配。在C ++中,过载分辨率已经足够疯狂了。

答案 1 :(得分:3)

Keep it simple, silly:

template<class U>
StereoSmp<TE> operator* (const StereoSmp<TE>& a, U b);

或如果适用:

StereoSmp<TE> a {/* ... */};
double b = /* ... */;
auto c = a * static_cast<float>(b);
  

为什么它不会自动将double转换为float?

因为模板扣除发生在之前可能的转换被考虑在内。如果您使用a*b aStereoSmp<float>一个b致电double,则模板替换将在floatdouble之前失败可以考虑转换,名称查找将继续,直到缺少候选人。

此过程称为Template argument deduction

答案 2 :(得分:2)

虽然Yakk的回答可能是这个特定情况下的最佳答案,但我想指出您可以阻止此扣减冲突并获得预期结果(通过StereoSmp<float>,推导TE为{{1通过使另一个参数不适用于演绎:

float

相关阅读:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3766.html

答案 3 :(得分:0)

  

为什么它不能自动将double转换为float?我该怎么做才能允许类型之间的自动转换?

这不是转换问题,它是模板参数推断问题。由于声明的格式为:

StereoSmp<TE> operator* (const StereoSmp<TE>& a, TE b)

...操作数类型为StereoSmp<float>double,C ++推理规则不起作用,因为它们没有考虑double可转换为float。这些规则由语言规范指定; 为什么他们不考虑潜在的转换的原因可能是因为&#34;它会使演绎非常复杂化,否则&#34;。规则已经够复杂了!

您当然可以将double参数投射到float,它会正常工作。此外,您可以使operator*成为StereoSmp的成员函数,或者您可以独立地参数化类型参数的类型:

template <class TE, class U> StereoSmp<TE> operator* (const StereoSmp<TE>& a, U b);