使用构造函数继承来提供兄弟类型之间的转换

时间:2015-03-12 16:16:02

标签: c++ templates c++11 constructor

我想允许以下行为:

struct SignalBase {};

struct Signal1 : public SignalBase
{ using SignalBase::SignalBase; };

struct Signal2 : public SignalBase
{ using SignalBase::SignalBase; };

int main()
{ 
    Signal1 s1;
    Signal2 s2(s1);
}

当然,这不起作用,因为SignalBase没有构造函数接收派生类型,并且复制构造函数不会继承using子句。

我试图用SignalBase中的模板构造函数来解决这个问题:

// External function:
template<typename Derived, typename Base>
constexpr bool isDerived()
{
   return std::is_base_of<Base, Derived>::value and
      !std::is_same<Base, Derived>::value;
}

struct SignalBase
{
   template<typename Signal>
   SignalBase(Signal const& s)  // (1)
   { static_assert(isDerived<Signal, SignalBase>(), "Invalid copying"); }
};

由于构造函数(1)不能与复制构造函数混淆(如果我没错,模板构造函数不被认为是复制构造函数,因为非模板复制构造函数优先于模板构造函数,如果它们具有相同的签名作为实例化后的拷贝构造函数。)

因此,构造函数(1)应该在派生类中继承:

// struct Signal1 inherits:
template<typename Signal>
Signal1(Signal const& s)  // (2)
{ static_assert(isDerived<Signal, SignalBase>(), "Invalid copying"); }

// struct Signal2 inherits:
template<typename Signal>
Signal2(Signal const& s)  // (3)
{ static_assert(isDerived<Signal, SignalBase>(), "Invalid copying"); }

和以下一行:

Signal2 s2(s1);

应该使用Signal = Signal1实例化(3),这是一个Signal的派生类,并且不会因static_assert子句而导致错误。

但是这并没有发生,因为编译错误表明没有找到Signal1Signal2的转换。

为什么基础构造函数没有被正确继承,以及在派生类中真正继承的是什么?

注意:在我的实际代码中(为简单起见未在此示例中显示),派生信号是模板,而转换运算符仅适用于显式转换(使用(Type)object运算符) ,在我在函数之间发送对象的地方使行太长。这就是为什么我想通过构造函数来寻找方法来实现它。

注意2 :请关注C ++问题(实际上是继承?)而不是其他OOP注意事项(例如,从基础clases构造派生对象是否有意义?) ,因为这是我真实代码的一个非常简化的例子。

1 个答案:

答案 0 :(得分:2)

通过添加第二层基类,可以在没有模板的情况下完成:

class SignalBase
{
    /* all the members */
};

struct CopyableSignalBase : SignalBase
{
    // not actually a copy constructor, so using will pick it up
    CopyableSignalBase(const SignalBase& src) : SignalBase(src) {}

    // make all other (not copy and not default) constructors available too
    using SignalBase::SignalBase;

    // since using doesn't introduce default constructor, provide it
    // if and only if SignalBase had one
    CopyableSignalBase() = default;
};

struct Signal1 : public CopyableSignalBase
{ using CopyableSignalBase::CopyableSignalBase; };

struct Signal2 : public CopyableSignalBase
{ using CopyableSignalBase::CopyableSignalBase; };

请注意,根据this feature matrix,在VS14之前,Visual Studio根本无法处理继承构造函数。但是没有构造函数继承,整个问题就毫无意义。