C++ 用C+指定协变/逆变行为+;模板

C++ 用C+指定协变/逆变行为+;模板,c++,scala,types,C++,Scala,Types,我正在研究Scala中的parboiled2,它有一种有趣的方式,可以使用协变/逆变子类型对类型系统中的解析器行为进行编码: 我很好奇,如果C++与模板元编程可以实现类似的事情。 我猜想协变行为可以用继承来模拟,但是C++中的逆变项< P>,像其他OO语言一样,子类型一般用继承来表示。 但是,我们不能通过继承来建模协方差和逆变关系,因为无法列出类的基类(没有任何各种反射建议,它们还没有进入语言) 允许这种行为的最简单方法是允许协变和逆变模板类基于相关类型的关系进行转换 协方差 如果派生的是-a

我正在研究Scala中的parboiled2,它有一种有趣的方式,可以使用协变/逆变子类型对类型系统中的解析器行为进行编码:

我很好奇,如果C++与模板元编程可以实现类似的事情。

我猜想协变行为可以用继承来模拟,但是C++中的逆变项

< P>,像其他OO语言一样,子类型一般用继承来表示。 但是,我们不能通过继承来建模协方差和逆变关系,因为无法列出类的基类(没有任何各种反射建议,它们还没有进入语言)

允许这种行为的最简单方法是允许协变和逆变模板类基于相关类型的关系进行转换

协方差 如果
派生的
是-a
基本的
,那么
协变的
“应该是-a”
协变的

通常,解决方案是使
协变
协变
继承,但我们目前无法找到
,只给出
派生
。但是,我们可以通过为
协变
编写一个构造函数来启用转换,该构造函数采用任何
协变

然而 这有一个主要缺点:您需要手动实现转换,并且要注意,意外事件可能会破坏您返回转换的能力(例如,如果您定义协变容器类型,这将是一个令人头疼的问题)

本质上,在反射允许我们自动化这种继承关系之前,转换是实现这一点的唯一方法,我不建议在任何复杂的情况下使用它。一旦你将
T
的对象存储在协变/逆变类中,你就会受到伤害

这里有一个链接来说明它的工作原理

template <typename T>
struct Covariant {
    template <typename Derived>
    Covariant(const Covariant<Derived>& derived, 
              std::enable_if_t<std::is_base_of_v<T, Derived>>* = nullptr)
    {
        /* Do your conversion here */
    }
};
template <typename T>
struct Contravariant {
    template <typename Base>
    Contravariant(const Contravariant<Base>& base,
                  std::enable_if_t<std::is_base_of_v<Base, T>>* = nullptr)
    {
        /* Do your conversion here */
    }
};