【问题标题】:Is there a way to do constructor delegation using a conditional in C++11?有没有办法在 C++11 中使用条件进行构造函数委托?
【发布时间】:2015-05-24 06:00:59
【问题描述】:

我正在尝试使用 C++11 委托功能来构造一个以输入值为条件的类。这甚至可能吗?下面的代码在语法上不正确,但我把它放在这里是为了澄清。

enum MyEnum { A, B };

typedef struct {
  int val;
  MyEnum e;
} MyStruct;

class Foo {
public: 
  Foo(MyStruct a, MyStruct b) {} // a.e == A and b.e == B (assert checked)
  Foo(MyStruct x) {
    if (x.e == A) {
      return Foo(x, {0, B});
    } else {
      return Foo({0, A}, x);
    }
  }
};

【问题讨论】:

  • 对于Foo,对复制或移动 ctor 的可能省略的调用是否不可接受? MyStruct 怎么样?

标签: c++ c++11 constructor delegation


【解决方案1】:
Foo(MyStruct x):
  Foo(
    (x.e==A)?x:MyStruct{0,B},
    (x.e==A)?MyStruct{0,A}:x
  )

是一种直接的方法。请注意,相同的 ctor 被委派给,但参数发生了变化。这与您的示例一致,但可能不是您真正的问题。


现在,假设您有一个更复杂的问题。您真的希望根据运行时值调用不同的构造函数吗?

如果我们希望根据运行时值调用不同的 ctor,我们可能不得不依赖(希望省略)复制或移动 ctor。

简单的方法就是

Foo(MyStruct x):
  Foo( (x.e==A)?
    Foo{x, {0,B}}:
    Foo{{0,A}, x}
  )
{}

我们使用不同的Foo 调用Foo 复制/移动ctor,具体取决于x.e。这有阻塞省略的小问题。

此时您应该停下来。因为下一步很疯狂。


这是避免构造候选 Foos 的一种过于花哨的方法,我认为甚至允许省略(不知道编译器是否真的会这样做):

template<class T>
struct delayed_construct {
  void const* data;
  T(*func)(void const*);
  template<class F>
  delayed_construct( F const& f ):
    data(&f),
    func([](void const* ptr)->T{
      F const& f = *static_cast<F const*>(ptr);
      return f();
    })
  {}
  T operator()() const {
    return func(data);
  }
};
struct Foo {
  explicit Foo( delayed_construct<Foo> d ):Foo(d()) {}
  Foo(MyStruct a, MyStruct b) {}
  Foo(MyStruct x):
    Foo( (x.e==A)?
      delayed_construct<Foo>{[&]()->Foo{
        return {x, {0,B}};
      }}:
      delayed_construct<Foo>{[&]()->Foo{
        return {{0,A}, x};
      }}
    )
  {}
};

它做了一堆非常复杂的东西,让你在调用两个不同的ctors之间做出选择。如果您不选择要调用的 ctor,甚至不会评估 ctor 的参数。

delayed_construct&lt;Foo&gt; 基本上是一个std::function&lt;F()&gt;,它假定它的生命周期将是一个临时的,这样做可能会受到编译器稍微更容易的优化。

我相信该标准允许在 Foo(MyStruct x) 中创建的 lambda 中构造的 Foo 直接构造我们从中调用它的 Foo。我可能是错的,而且很有可能即使我是对的,编译器也可能不会这样做。

【讨论】:

  • 在您的回答中,您假设三元运算符?: 的所有三个操作数都被评估,实际上它只评估第二个或第三个参数,具体取决于第一个参数的值。它从不计算所有三个操作数。
  • @RalphTandetzky 我认为已修复。抱歉,脑子有问题。
  • 您的模板代码中仍然存在一些错误:this 的右值引用必须在 operator() 上删除。 static_cast 不能抛弃 const。因此,在那里写static_cast&lt;F const*&gt;。在这些更改之后,您的代码在 gcc 和 C++11 和 C++14 模式下运行。
  • 是什么让你觉得,移动或复制实际上被省略了?
  • @ralph 我认为省略是合法的,因为一切都是候选对象,并且以复制/移动 ctor 结尾。如果它没有,或者我认为它是合法的,我不会感到惊讶。
猜你喜欢
  • 2013-01-04
  • 1970-01-01
  • 2012-12-31
  • 1970-01-01
  • 2016-10-02
  • 2020-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多