我不明白为什么该程序无法使用-std = c ++ 14在g ++ 7.3或clang ++ 5.0中编译。
如图所示,可以从A
初始化 const int
。也可以从A
创建对const int
的const引用,但是用f(const A &)
到const int
的调用失败。为什么?
#include <iostream>
struct V {
int i;
template <class T>
V(const T &t) : i{t} {}
};
struct A {
int i;
A(V v) : i{v.i} {}
};
void f(const A &) {}
int main() {
const auto i = 42;
const A a1{i}; // OK
std::cout << a1.i << '\n'; // 42
const A &a2 = A{i}; // OK
std::cout << a2.i << '\n'; // 42
f(i); // no matching function for call to 'f'
return 0;
}
答案 0 :(得分:0)
出于函数调用的目的,将i
转换为A
将需要两次用户定义的转换(int -> V -> A
)。该标准对每个隐式转换序列都设置了单个用户定义转换的硬性限制。
如果您尝试将a2
直接绑定到i
,也会发生同样的情况。因此,在为A{i}
提供参数时,也需要进行功能样式转换(f
。
答案 1 :(得分:0)
应用f(i);
,copy initialization。并且i
(类型为const int
)需要转换为A
,需要两个用户定义的转换;从const int
到V
,以及从V
到A
。但是在一个隐式转换序列中仅允许一个用户定义的转换。
Bot const A a1{i};
和const A &a2 = A{i};
是direct initialization,只有一个从i
(类型为const int
)到参数A
的隐式转换的构造函数(即V
)是必需的,因此它们可以正常工作。
请注意复制初始化和直接初始化之间的区别,
此外,复制初始化中的隐式转换必须直接从初始值设定项产生T,而例如直接初始化需要从初始值设定项到T的构造函数的参数的隐式转换。
作为解决方法,您可以先将i
进行显式转换,然后再将其传递给f()
。
答案 2 :(得分:0)
这里需要两个连续的隐式类型转换,但是C ++可以为您做一次转换隐式转换。如果要让编译器为您生成正确的类型化代码,请对函数template
使用f
,如下所示。
template <typename T>
void f(const T & x) { std::cout << x << std::endl;}
之所以需要两种类型转换,是因为只有一个构造函数在结构中采用类型V
。如果要摆脱两种类型的转换作为第二种解决方案,则可以添加另一个将int
作为参数的构造函数,如下所示:
struct A {
int i;
A(V v) : i{v.i} {}
A(int theI) : i{theI} { }
};
答案 3 :(得分:0)
副本初始化不支持两个用户定义的转换。解决该问题的简单方法是在将f
传递给功能f(A(i))
的同时用A包裹i