以下工作正常(正如人们所期望的那样):
struct X {};
struct A
{
operator X const& ()
{
static const X value{};
return value;
}
};
int main()
{
A a;
X x = a;
}
但这还不是很清楚:
template<typename T>
struct X {};
struct A
{
template<typename T>
operator X<T> const& ()
{
static const X<T> value{};
return value;
}
};
int main()
{
A a;
X<int> x = a;
}
GCC 4.9 说 error: conversion from ‘A’ to non-scalar type ‘X<int>’ requested
而 clang 3.4 没有问题。
如果删除 const
或 &
从转换函数或者如果你写 X<int> const &x = a
那么 GCC 也很高兴。
所以 GCC 只有在目标类型是 const &
时才会找不到转换函数到模板类,您请求转换为非 const &
该类的对象。这是正确的行为吗?我试图阅读标准,但重载规则让我很困惑。
最佳答案
是的,这是 gcc 中的错误。这几乎就是 core DR976 ,唯一的区别是在他们的示例中目标类型是非类类型:
struct F {
template<class T>
operator const T&() { static T t; return t; }
};
int main() {
F f;
int i = f; // ill-formed
}
与您的示例一样,clang 接受而 gcc 拒绝此示例,无论选择的标准版本方言如何。
请注意,该 DR (14.8.2.3 [temp.deduct.conv]) 修改的条款不区分类别和非类别目标类型,因此该 DR 的决议适用于你的代码同样。
根据修订后的条款 14.8.2.3,编译器应该:
- 确定
P
,转换函数模板的返回类型,为X<T> const &
, 和A
, 所需的结果类型,如X<int>
; - 从
P
中删除引用, 给出X<T> const
; - 从
P
中去除 cv 限定条件, 给出X<T>
; - 推断
T
作为int
.
我建议在 https://gcc.gnu.org/bugzilla/ 上提交错误报告引用该 DR。
因为在您的情况下您正在转换为类类型,所以有一个可用的解决方法:
X<int> x1 = a; // fails
X<int> x2(a); // OK
X<int> x3 = X<int>(a); // also OK
在直接初始化中,考虑目标类型的构造函数(8.5p16); X<int>
的默认拷贝构造函数采用 X<int> const&
类型的参数,正如我们已经看到的那样,gcc 很乐意将 a
转换为.
关于c++ - 模板转换函数到 const-reference,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24491919/