C ++ 11中的隐式构造函数参数转换

时间:2013-06-27 09:47:07

标签: c++ c++11 types compiler-construction type-conversion

让代码符合以下代码:

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);

是否可以使用分配运算符?

3 个答案:

答案 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是否值得。隐含的转换往往会使程序更难理解,并且很快就会超过它们带来的明显好处。