为什么可以强制转换的泛型类型不会被隐式转换
Why does a generic type that can be casted not get implicitly converted?
我有一个类A
和一个类B
,两者都是泛型的,类型参数T
。A<T>
的对象可以强制转换为B<T>
。我在B
上有一个通用运算符重载,我希望能够调用A
对象和B
对象,其中A
对象被隐式转换。
当我尝试这样做时,它无法编译:
template <typename T>
class A {};
template <typename T>
class B {
public:
B() {}
B(const A<T> &a) {}
};
template <typename T>
B<T> operator*(const B<T> &obj1, const B<T> &obj2) {
return B<T>(); // doesn't matter
}
int main() {
A<int> objA;
B<int> objB;
B<int> combined1 = objA * objB; // error: operator* isn't defined on these types
B<int> combined2 = static_cast<B<int>>(objA) * objB; // fine
return 0;
}
但是,当 A 和 B 不是通用的时,它可以正常工作:
class A {};
class B {
public:
B() {}
B(const A &a) {}
};
B operator*(const B &obj1, const B &obj2) {
return B(); // doesn't matter
}
int main() {
A objA;
B objB;
B combined1 = objA * objB; // fine
B combined2 = static_cast<B>(objA) * objB; // also fine
return 0;
}
这是为什么呢?是否使运算符重载泛型,这意味着无法推断类型?
一般来说,在进行参数推导时不允许隐式转换,我可以认为派生到基数是允许的。表达式
B<int> combined1 = objA * objB;
期望为objA * objB
找到可行的重载,包括 ADL 发现的重载,一种可能是:
template <typename T>
B<T> operator*(const A<T> &obj1, const B<T> &obj2) {...}
但是没有找到,你提供的重载不是候选的,因此调用失败,但是如果你向运算符提供显式模板参数,那么就没有什么可推断的,通过转换构造函数的隐式转换将允许调用:
B<int> combined1 = operator*<int>(objA, objB);
但我不会那样做,坚持演员阵容,更好地解释意图。
您可以在调用模板函数class A
中定义友元函数
template <class T>
class B;
template <typename T>
class A {
friend B<T> operator*(const B<T> &obj1, const B<T> &obj2) {} # here call template function
};
template <typename T>
class B {
public:
B() {}
B(const A<T> &a) {}
};
template <typename T>
B<T> operator*(const B<T> &obj1, const B<T> &obj2) {
return B<T>(); // doesn't matter
}
int main() {
A<int> objA;
B<int> objB;
B<int> combined1 = objA * objB; // fine
B<int> combined2 = static_cast<B<int>>(objA) * objB; // fine
return 0;
}
在参数推导期间,不会发生转换/提升,因此对于
objA * objB
在检查候选人超载的有效性时,不能推断出T
:
template <typename T> B<T> operator*(const B<T> &, const B<T> &);
因此,过载被拒绝。
解决此问题的一种方法是创建一个非模板函数。Asit 应该适用于类模板,一种方法是使用 friend
函数:
template <typename T>
class B {
public:
B() {}
B(const A<T>&) {}
friend B operator*(const B&, const B&) { return /*...*/; }
};
现在,objA * objB
考虑过载B<int> operator*(const B<int>&, const B<int>&)
并且可以进行转换以查看函数是否可行(确实可行)。
演示
相关文章:
- 使用泛型类型推送到堆栈时出现问题
- 如何在容器中指定模板化别名的泛型类型
- 具有模板专用化的泛型类型转换
- C++存储泛型 T 类型类的向量
- 如何在C++中返回没有模板的泛型类型?
- 如何在带有约束 (C++) 的函数中使用泛型类型
- 模板函数重载(泛型类型与模板模板类型)选择正确的重载
- 泛型类型别名,它们彼此不兼容
- 泛型类型转换
- 重载泛型类型的模板类时检查运算符=时的自赋值
- 在C++中,如何根据类中的参数返回不同的泛型类型
- C++错误 C2227:'->looseHealth'左侧必须指向类/结构/联合/泛型类型
- 使用泛型类型显式实例化函数模板
- 函数模板中的无效转换错误,返回值取决于其泛型类型
- 如何确保 "<<" 运算符适用于模板化 ADT 定义中的任何泛型类型?
- 仅当泛型类型的值是指针时,才删除该值
- 错误c++visual studio c2227左侧'->;Init';必须指向类/结构/联合/泛型类型
- 用于泛型类型上的泛型操作的SFINAE
- 为什么可以强制转换的泛型类型不会被隐式转换
- 类型转换泛型c++