让代码符合以下代码:
class A{
public:
A(int x){}
};
class B{
public:
B(A a){};
};
int main() {
B b = 5;
return 0;
}
编译编译器时抱怨:
/home/test/main.cpp:80: candidate constructor not viable: no known conversion from 'int' to 'A' for 1st argument
我不想创建B(int)
构造函数 - 我希望编译器将此int
隐式转换为A
对象。
修改
直接初始化的工作原理如下:
B b(5);
是否可以使用分配运算符?
答案 0 :(得分:1)
要明确:
B b = 5;
是“复制初始化”而非分配。 (见http://www.gotw.ca/gotw/036.htm)。
在这种情况下,您要求编译器首先执行两个隐式的用户定义转换,即int -> A, A -> B
,然后将临时B
对象传递给B b
的复制构造函数。允许编译器忽略临时对象,但从语义上讲,你仍然要求语言跨类型进行两次跳转。
编程语言中的所有隐式行为都具有内在的可怕性。为了一点点语法糖,我们要求c ++“做一些魔术才能使它正常工作”。意外的类型转换可能会破坏大型复杂程序的破坏。否则,每次编写新函数或新类时,都必须担心它可能影响的所有其他类型和函数,并且副作用会在代码中波动。
你真的想要来自int
- >的隐式转换吗? apple
- > horse
- > horse_power
- > aeroplane
?
出于这个原因,c ++只允许一个隐式的用户定义转换:
12.3转化[class.conv]
1类对象的类型转换可以由构造函数和转换函数指定。这些转换称为用户定义的转换,用于隐式类型转换(第4节),初始化(8.5)和显式类型转换(5.4,5.2.9)。
4最多只有一个用户定义的转换(构造函数或转换函数)隐式应用于单个值。
您最好使用显式强制转换或“直接初始化”,这两者都使编译器和协作者明确了解您要执行的操作。传统或新的统一初始化语法都有效:
B b(5);
B b{5};
B b = {5};
答案 1 :(得分:0)
使用直接初始化:
B b(5);
答案 2 :(得分:0)
您可以使用转化构造函数constrained转换为A
。
class B {
public:
// It doesn't hurt to keep that one
B(A a){};
template<
typename T
, EnableIf<std::is_convertible<T, A>>...
>
B(T&& value)
{
// How to use the value
A a = std::forward<T>(value);
}
};
// Now B b = foo; is valid iff A a = foo; is, except for a few exceptions
确保您了解EnableIf
约束的目的。如果你不使用它,你将面临粗糙的编译错误,或者更糟:完全没有错误。您还应该仔细考虑是否可以从潜在的许多类型转换B
是否值得。隐含的转换往往会使程序更难理解,并且很快就会超过它们带来的明显好处。