以下工作正常(正如人们所期望的那样):
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也很满意。
因此,如果目标类型是模板类的const &
并且您请求转换为该类的非const &
对象,则GCC只能找不到转换函数。这是正确的行为吗?我尝试阅读标准,但重载规则对我来说非常混乱。
答案 0 :(得分:5)
是的,这是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
。我建议在引用该DR的https://gcc.gnu.org/bugzilla/上提交错误报告。
因为在您转换为类类型的情况下,有一种解决方法可用:
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
。