Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么';t我的模板函数升级';int';至';T';,其中';T';=';双倍';?_C++_Templates_C++11_C++14_Type Promotion - Fatal编程技术网

C++ 为什么';t我的模板函数升级';int';至';T';,其中';T';=';双倍';?

C++ 为什么';t我的模板函数升级';int';至';T';,其中';T';=';双倍';?,c++,templates,c++11,c++14,type-promotion,C++,Templates,C++11,C++14,Type Promotion,我有一个用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 addi

我有一个用
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;
}
然后编译器给我一条类似于-
不匹配“operator+”(操作数类型为“myClass”和“int”)。候选人是。。。注意:参数“const T”(“double”和“int”)的类型存在冲突。


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

编译器在重载解析时无法为
运算符+
找到合适的候选者,因为
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);
}
模板
myClass运算符+(myClass lhs、常数T2和rhs){
返回lhs+=T1(rhs);
}

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

在您的情况下,
T
的两次扣减产生了
double
int
,这两种扣减不相同,因此扣减失败

您可以只使用一个函数参数进行模板参数推导,并取消对另一个函数参数的推导:

模板
void foo(myClass arg1,typename std::common_type::type arg2);
//                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
请注意,
std::common_type::type
本质上只是
T
,但由于
arg2
的类型现在是一个依赖类型(其名称出现在
的右侧),因此无法推断。因此,只有第一个参数参与推导并明确地生成
T=double
,然后第二个函数参数的类型只有
double
,并且通常会进行转换


根据经验,模板参数推断不会交叉

模板类型推断会遇到问题

在推导
T
的值时,两个参数被赋予“同等地位”,在这种情况下,两个参数不一致——一个说
T
应该是
int
,另一个说
T
应该是
double

解决这个问题的正确方法是使用Koenig操作符

将类中的
+=
+
交为好友,并实现内联:

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;
  }
};
模板
类myClass{
//等
公众:
友元myClass运算符+(myClass lhs、常量T和rhs){
lhs+=rhs;
返回标准::移动(lhs);
}
朋友myClass和运算符+=(myClass和lhs、常量T和rhs){
//做加法,取决于a`
归还*这个;
}
};
这种技术有点奇怪。它根据类的模板类型创建非
template
运算符。然后,当您调用
+
+=
时,可以通过ADL(Koenig查找)找到这些文件


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

try
myObj\u double\u 2=myObj\u double\u 2+5.0是-这将不会有任何困难,但它并不能解决我所问的问题(尽管这是一个简单而明显的解决方案)。不存在int->double“promotion”。@LightnessRacesinOrbit:有点像。例如,声明
void foo(double)foo(3)
是完全合法的,并且做的事情与
foo((双)3)
foo(3.0)
一样。所以这里的问题更微妙。@NateEldredge:这种隐式转换肯定存在,但这不是“提升”,是吗?如果
T1
T2
相等,这可能会导致不必要的复制-按值获取参数是否允许移动(在
int
double
的情况下可能会更快吗?)@chrisb2244您可以部分地专门处理
T1==T2
这种情况,如果您只想允许隐式转换,那么就初始化
T1
类型的局部。这很完美,但我认为您的意思是
typename std::common\u type::type
。您的解决方案还允许
const
de>&
待添加,这是非常好的
common_type
衰减类型;这里可能不相关,但需要记住。还可以在
myClass
中添加
T
的typedef(即
value_type
),并使用
模板myClass操作符+(myClass lhs,typename myClass::value_type const&rhs)
@LightnessRacesinOrbit:True。我们可能应该有一个
std::nondeduced::type
,不是因为它比
std::common_type::type
好,而是因为它使意图显而易见。@mAlters:
std::kill_Desculacity
template <typename T1, typename T2, size_t a>
myClass<T1,a> operator+(myClass<T1,a> lhs, const T2& rhs) {
    return lhs += T1(rhs);
}
template <typename T, std::size_t A>
void foo(myClass<T, A> arg1, typename std::common_type<T>::type arg2);
//                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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;
  }
};