模板化操作符实例化和类型转换
Templated operator instantiation and type conversion
这是写给那些c++高手的
考虑以下代码:
class X { };
template <class T>
class Mistake {
public:
T x;
Mistake(const T& k) : x(k) { }
Mistake(const X&) : x(1) { }
void print() { cout << x << endl; }
};
template <class T>
Mistake<T> operator+(const Mistake<T>& a, const Mistake<T>& b)
{
return Mistake<T>(a.x + b.x);
}
我有一个类"错误",我想对它进行加法运算。当我尝试:
X a, b;
Mistake<int> foo = a + b;
得到一个编译错误;编译器似乎没有意识到必须实例化模板操作符+。
另一方面,如果在前面添加以下代码:
Mistake<int> operator+(const Mistake<int>& a, const Mistake<int>& b)
{
return Mistake<int>(a.x + b.x);
}
那么一切都好。有人知道为什么吗?我怀疑编译器无法确定要实例化什么,因为从类X到类错误需要类型转换,但我不知道如何解决这个问题,除非根本不使用模板。
顺便说一下,在类内部将操作符定义为友元也是不行的。谢谢!
虽然其他人已经对你的问题提出了可能的解决方案,但我想指出发生了什么,以及为什么你的期望不能满足。
这里的问题是在执行类型推导时不考虑用户定义的转换。当编译器看到这个表达式时:a + b
其中a
和b
均为X
类型,operator +
的签名如下:
template <class T>
Mistake<T> operator+(const Mistake<T>& a, const Mistake<T>& b)
编译器要做的第一件事是尝试推导T
,使操作符的形参类型与实参类型完全匹配。如果这是不可能的,编译器立即放弃,不考虑可能的转换构造函数,并关注其他候选函数(或函数模板)。
考虑到上面的情况,很明显,没有办法使Mistake<T>
变成恰好 X
,无论你选择的T
是什么(Mistake<int>
不是X
, Mistake<X>
不是X
,等等)。因此,替换失败,编译器不知道如何解析调用,因为周围没有其他候选对象。
另一方面,当你有这个:
Mistake<int> operator+(const Mistake<int>& a, const Mistake<int>& b)
不涉及类型演绎,因为上面不是函数模板。因此,编译器在尝试解析调用时将考虑用户定义的转换,并且由于Mistake<int>
有一个接受X
的构造函数,因此上面的operator +
被认为是可行的候选者,并且它被选中。
我认为没有办法。你能做到的最纯粹的是
Mistake<int> foo = static_cast<Mistake<int>>(a) + static_cast<Mistake<int>>(b);
或者使用一个额外的重载来匹配非对称操作数类型:
template <class T, class U>
Mistake<T> operator+(const Mistake<T>& a, U const& b) {
return a + static_cast<Mistake<T>>(b);
}
// and later:
foo = Mistake<int>(a) + b;
完整的实时演示:http://ideone.com/ki14GO
#include <iostream>
class X { };
template <class T>
class Mistake {
public:
T x;
Mistake(const T& k) : x(k) { }
Mistake(const X&) : x(1) { }
void print() { std::cout << x << std::endl; }
};
template <class T>
Mistake<T> operator+(const Mistake<T>& a, const Mistake<T>& b) {
return Mistake<T>(a.x + b.x);
}
template <class T, class U>
Mistake<T> operator+(const Mistake<T>& a, U const& b) {
return a + static_cast<Mistake<T>>(b);
}
template <class T, class U>
Mistake<T> operator+(const U& a, Mistake<T> const& b) {
return static_cast<Mistake<T>>(a) + b;
}
int main()
{
X a, b;
Mistake<int> foo = static_cast<Mistake<int>>(a) + static_cast<Mistake<int>>(b);
foo = Mistake<int>(a) + b;
foo = a + Mistake<int>(b);
}
我认为编译器在推断a + b
的类型时存在问题。
你可以定义:
X operator+(const X & a, const X & b) {
return a /* ??? or something else */;
}
如果你有办法告诉a + b
的答案是什么X
相关文章:
- 检查某些类型是否是模板类 std::optional 的实例化
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 将显式实例化的函数模板与转换匹配
- 实例化模板时,我是否必须显式显示参数包中的类型?
- 无法将模板子类强制转换为其他模板实例化
- 在实例化之前推断函数模板的返回类型
- 使用用户定义的类型 UDT 实例化 std::atomic<>。如果 UDT 具有虚函数,则 l 墨水将失败。为什么?
- 类模板实例化中的类型转换
- 引用的静态强制转换强制模板实例化,其中不完整的类型很好
- 有没有办法将一对元组剥离为可变参数模板类型或实例化具有可变参数类型的东西?
- 如何在尝试为某些非类型值实例化模板子类方法时产生编译器错误
- 使用标准类型的动态类型信息实例化标识符
- 纯抽象类和派生类型的实例化
- 模板类型名实例化错误
- 使用bool非类型参数实例化类模板时出错
- 在没有数据重复的情况下强制转换/实例化/转换为子类/超类
- std::conditional 的可变模板化使用,其中一种类型是实例化失败
- 模板化操作符实例化和类型转换
- "*"标记之前的预期构造函数、析构函数或类型转换 模板化链表
- 如何从另一个实例的类型动态实例化新实例?C++