为什么我的模板化函数不会将'int'提升为'T',其中'T'='double'?

chr*_*244 21 c++ templates c++11 type-promotion c++14

我有一个模板化的类typename T.它包含一个功能,

template <typename T, size_t a>
myClass<T,a> operator+(myClass<T,a> lhs, const T& rhs) {
    return lhs += rhs;
}

myClass<T,a> myClass<T,a>::operator+=(const T& rhs) {
    // Do addition, depends on 'a'.
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

例如,当我打电话给你的时候

myClass<double, 2> myObj_double_2(constructor args);
myObj_double_2 = myObj_double_2 + 5.2;
Run Code Online (Sandbox Code Playgroud)

我没有问题.

如果我打电话

myObj_double_2 = myObj_double_2 + 5;
Run Code Online (Sandbox Code Playgroud)

然后编译器给我一个像 - 的消息No match for 'operator+' (operand types are 'myClass<double, 2ul>' and 'int'). Candidates are ... note: deduced conflicting types for parameter 'const T' ('double' and 'int').

我是否可以以某种方式编写代码以允许传递具有转换的其他类型T(因为,例如,double(5)是一个有效的构造函数调用)?

Ker*_* SB 32

使用模板参数推导时,一个模板参数的所有推导必须具有相同的结果.

在你的情况下,两个扣除T生产doubleint,这是不一样的,所以扣失败.

你可以做的只是使用一个函数参数进行模板参数推导,并使另一个函数参数不受限制:

template <typename T, std::size_t A>
void foo(myClass<T, A> arg1, typename std::common_type<T>::type arg2);
//                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

请注意,这std::common_type<T>::type基本上只是T,但因为类型arg2现在是一个依赖类型(它的名称出现在a的右侧::),所以不推断它.因此,只有第一个参数参与演绎并且T = double明确地产生,然后第二个函数参数只有类型double,并且通常发生转换.

根据经验,模板参数推导不会交叉::.

  • 也可以在`myClass`中添加`T`(即`value_type`)的typedef并使用`template <typename T1,size_t a> myClass <T1,a> operator +(myClass <T1,a> lhs, typename myClass <T1,a> :: value_type const&rhs);` (3认同)
  • @MSalters:`std :: kill_deduceacity_t <T>`:-) (3认同)

101*_*010 17

重载解析的编译器无法找到合适的候选者,operator+因为T已经被扣除,double而literal 5是一个整数.解:

template <typename T1, typename T2, size_t a>
myClass<T1,a> operator+(myClass<T1,a> lhs, const T2& rhs) {
    return lhs += T1(rhs);
}
Run Code Online (Sandbox Code Playgroud)

  • @ chrisb2244你可以部分专门研究`T1 == T2`的情况 (4认同)

Yak*_*ont 8

您遇到模板类型扣除问题.

当推导出两个论证的价值时T,这两个论点都被赋予了"同等的地位" ,在这种情况下,两个论点不同意 - 一个说T应该是int,另一个说T应该是double.

解决这个问题的正确方法是Koenig运营商.

制作+=+之类friend类的S和实现内联:

template<class T, size_t a>
class myClass {
  // etc
public:
  friend myClass operator+(myClass lhs, const T& rhs) {
    lhs += rhs;
    return std::move(lhs);
  }
  friend myClass& operator+=(myClass& lhs, const T& rhs) {
    // do addition, depends on `a`
    return *this;
  }
};
Run Code Online (Sandbox Code Playgroud)

这种技术做的很奇怪.它template根据类的模板类型创建非运算符.然后在调用+或时通过ADL(Koenig查找)找到它们+=.

每个模板实例化都会获得其中一个运算符,但它们不是模板运算符,因此const T&不会推导出,并且转换按预期进行.