【问题标题】:Implicit constructor argument conversion in C++11C++11 中的隐式构造函数参数转换
【发布时间】:2013-06-27 09:47:07
【问题描述】:

让我们考虑以下代码:

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

可以改用赋值运算符吗?

【问题讨论】:

  • 不,你不能隐含地这样做。
  • 为什么我不能隐含地做到这一点?
  • 尝试从 A 中添加赋值运算符,例如 B& operator = (const A& a);B& operator = (A a);
  • 是的,我已经尝试过了,但仍然出现同样的错误。

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


【解决方案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};

【讨论】:

    【解决方案2】:

    改用直接初始化:

    B b(5);
    

    【讨论】:

    • 谢谢,它有效,但我很想使用赋值运算符 - 有可能吗?
    • 咳嗽 B(int) 构造函数 - 抱歉 ;) 咳嗽
    • @danilo2 您的代码没有使用赋值运算符。它正在使用复制初始化。
    • @Angew 那么是否可以创建一些copy constructors 以使此代码按我的意愿工作?
    • 很伤心:(谢谢大家:(
    【解决方案3】:

    您可以在转换为A 时使用constrained 的转换构造函数。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-02
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-26
      • 1970-01-01
      相关资源
      最近更新 更多