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

Use constructor inheritance to provide conversion between sibling types

我想允许以下行为:

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) 不能与复制构造函数混淆(如果我没记错的话,模板构造函数不被视为复制构造函数,因为非模板复制构造函数优先于模板构造函数,如果它们具有相同的签名作为实例化后的复制构造函数)。

所以,constructor(1)应该在derived中继承class:

// 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 的派生 class,不会因 static_assert 子句而导致错误。

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

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

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

注意 2:请关注 C++ 问题(它真的被继承了吗?)而不是其他 OOP 考虑因素(例如,构造派生对象是否有意义来自基本类?),因为这是我的真实代码的一个非常简化的例子。

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

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 根本无法处理继承构造函数。但是如果没有构造函数继承,整个问题就毫无意义。