如何强制实际继承对象?

时间:2015-07-31 13:15:24

标签: c++ templates inheritance typetraits virtual-inheritance

是否可以定义一个只能从虚拟继承的基类?也就是说,我们可以填写

中的点
struct Base {
    static_assert (..., "You may only inherit virtually from Base");
};

这样

struct A : public virtual Base {};

编译好,但

struct B : public Base {};

没有?当然,Base可能无法知道将从中继承的所有类型,但我们可能会天真地尝试在这里使用CRTP:

#include <type_traits>

template <typename taBase, typename taDerived>
struct VirtualBase : public taDerived, public virtual taBase {};

template <typename taDerived>
struct NonVirtualBase : public taDerived {};

template <typename T, typename U>
struct IsVirtualBaseOf : std::integral_constant <bool, 
    std::is_base_of <T, U>::value && 
    sizeof(NonVirtualBase <U>) == sizeof (VirtualBase <T, U>)
> {};

template <typename taDerived>
struct Base {
    static_assert (IsVirtualBaseOf <Base <taDerived>, taDerived>::value, "");
};

struct A : public virtual Base <A> {};
struct B : public Base <B> {};

这不起作用,因为在Base实例化时,A <Base>B <Base>仍然是不完整的类型,并在VirtualBaseNonVirtualBase中继承它们产生编译器错误。 (另外,std::is_base_of由于同样的原因而无法工作)

当然,我们可能会将static_assert移动到AB,但是因为这些类似于要定义的客户端类,我想通过定义强制执行虚拟继承Base。也许有一种方法可以通过包装A来延迟验证,直到BBase不再是不完整的类型,或者这可能是使用C ++概念实现的。欢迎任何建议。提前谢谢。

旁注:转发声明对象的继承意图的能力,但尚未定义,现在非常受欢迎,你不同意吗? E.g。

struct X {};

struct Y : public X;

struct Y : public X {};

修改

虽然这个问题确实是重复的,但我相信能够详细说明一个适用于我的用例的解决方案。但这不是这个问题的答案。正如peterchen在评论部分所指出的那样,继承层次结构已知可以进一步派生类,这对于解决我的情况中的问题至关重要。

首先,让我进一步解释用例。 Base通常是struct,通过继承Traits基础来承载NonConstructible概念。

struct Traits {
private:
    Traits ();
};

由于我们希望所有特征类都是不可构造的,但仍然是定义的类型,因此出现了对均匀性的渴望。为此,我们可能同意继承Traits。不同的用例可能要求覆盖(隐藏)特征类Base的不同元素。例如,

struct Base {
    typedef int SocketIdType;
    typedef short PortType;
    typedef char IpAddressType[4];
};

struct SpecialSocketIdTraits : public Base {
    typedef unsigned int SocketIdType;
};

struct SpecialPortTraits : public Base {
    typedef unsigned short PortType;
};

template <typename> struct Socket;

typedef Socket <SpecialSocketIdTraits> Socket1;
typedef Socket <SpecialPortTraits> Socket2;

通常需要组合这些独立覆盖的特征类。因此,我们引入了一个实用程序MergeTraits struct。

template <typename... taTraits>
struct MergeTraits : public taTraits... {};

我们希望这能使我们做到以下一般:

typedef MergeTraits <SpecialPortTraits, SpecialSocketIdTraits> SpecialSocketIdAndPortTraits;
typedef Socket <SpecialSocketIdAndPortTraits> Socket3;

但是,由于两个traits类都有::SocketIdType,因此查找不明确。考虑当前的情况表明,默认情况下在层次结构中具有虚拟继承可以解决模糊问题,但也可以满足您的期望。由于Base只会从一次继承而SpecialSocketIdTraits会隐藏::SocketIdType Base,因此我们保证SpecialSocketIdAndPortTraits::SocketIdType等于unsigned int }}。如果有另一个这样的

struct SpecialSocketIdTraits2 : public virtual Base {
    typedef long SocketIdType;
};

然后,::SocketIdTypeMergeTraits <SpecialSocketIdTraits, SpecialSocketIdTraits2>的查找将再次正确模糊。现在为解决方案,灵感来自peterchen的评论。我们可以检查包taTraits是否存在从特定基本特征继承的结构。然后可以验证这些继承是虚拟的。

template <typename...> struct Tuple;

template <typename, typename> struct ShouldMaybeVirtualInheritFrom;

template <typename B>
struct ShouldMaybeVirtualInheritFrom <Tuple <>, B> : std::true_type
{};

template <typename D, typename B>
struct ShouldMaybeVirtualInheritFrom <Tuple <D>, B> :
    std::integral_constant <bool,
        !std::is_base_of <B, D>::value || IsVirtualBaseOf <B, D>::value
    >
{};

template <typename D, typename... Ds, typename B>
struct ShouldMaybeVirtualInheritFrom <Tuple <D, Ds...>, B> :
    std::integral_constant <bool,
        (!std::is_base_of <B, D>::value || IsVirtualBaseOf <B, D>::value) &&
        ShouldMaybeVirtualInheritFrom <Tuple <Ds...>, B>::value
    >
{};

我的代码中的真正解决方案有点复杂,并利用一些已经存在的模板元编程工具作为语法糖,但这就是它归结为。我们现在可以在MergeTraits中使用此组件来检测来自Base的虚拟继承。

template <typename... taTraits>
struct MergeTraits : public taTraits... {
    static_assert (ShouldMaybeVirtualInheritFrom <Tuple <taTraits...>, Base>::value,
    "For all traits T in taTraits...: if T inherits from Base it should do so virtually.");
};

缺点是我们需要用这些断言的列表来污染MergeTraits,当然。但是,我们可以将检查委托给进一步派生的类,至少解决我的问题。

template <typename... taTraits>
struct MergeTraits : public taTraits... {};

template <typename... taTraits>
struct MergeFromBase : public MergeTraits <taTraits...> {
    static_assert (ShouldMaybeVirtualInheritFrom <Tuple <taTraits...>, Base>::value,
    "For all traits T in taTraits...: if T inherits from Base it should do so virtually.");
};

0 个答案:

没有答案