繁体   English   中英

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

[英]Implicit constructor argument conversion in C++11

让我们考虑以下代码:

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

是否可以改用赋值运算符?

只是要清楚:

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

改用直接初始化:

B b(5);

您可以使用在转换为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可从潜在的许多类型转换是否值得。 隐式转换往往会使程序更难理解,这很快就会超过它们带来的明显好处。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM