c++ - 带有 CRTP 的转发构造函数

标签 c++ clone crtp

我使用带有 CRTP 的模板类来实现克隆模式,第二个模板参数 Base 允许多级继承。当我尝试调用间接基类的构造函数时出现编译器错误。

class B
{
public:
    B() {} //trivial constructor
    virtual B* clone()=0;
};

template<class Base, class Derived>
class Clonable
    :public Base //weird, I know
{
public:
    virtual B* clone() {return new Derived(*this);}
};

class D1 : public Clonable<B, D1>
{
public:
    D1(int a); //non-trivial constructor. Different signature than B
};

class D2 : public Clonable<D1, D2>
{
public:
    D2(int a): D1(a) {} //compiler error here
}

到目前为止,我遇到的唯一解决方案是在 Cloneable 中使用可变参数模板构造函数,但我的编译器 (VC++11) 尚未实现它们。

最佳答案

您需要让您的克隆“中间人”类转发构造函数参数,或者更好(Luc Danton 建议)使用 C++11 构造函数继承。

因此,在 C++11 中很容易做到这一点,但在 C++03 中或使用尚不支持 C++11 参数转发或构造函数继承的当前编译器(例如 Visual)就没那么容易了C++10。

在我的旧博文 "3 ways to mix in a generic cloning implementation" 中讨论了在 C++03 中使用辅助参数转发器类实现此目的的一种方法。 .然后中间人(克隆实现)类可以是这样的:

template< class Derived, class Base >
class WithCloningOf
    : public progrock::cppx::ConstructorArgForwarder< Base >
{
protected:
    virtual WithCloningOf* virtualClone() const
    {
        return new Derived( *static_cast< Derived const* >( this ) );
    }

public:
    template< class ArgPack >
    WithCloningOf( ArgPack const& args )
        : progrock::cppx::ConstructorArgForwarder< Base >( args )
    {}

    std::auto_ptr< Derived > clone() const
    {
        return std::auto_ptr< Derived >(
            static_cast< Derived* >( virtualClone() )
            );
    }
};

我在之前的博文中讨论了 C++03 兼容的 ConstructorArgForwarder;它看起来像这样:

template< typename Type >
class ConstructorArgForwarder
    : public Type
{
public:
    typedef Type        Base;

    // TODO: remove
    virtual ~ConstructorArgForwarder() {}

    ConstructorArgForwarder( EmptyArgPack const& )
        : Base()
    {}

    template< class T01 >
    ConstructorArgForwarder(
        ArgPack< T01 > const& args
        )
        : Base( args.a01 )
    {}

    template< class T01, class T02 >
    ConstructorArgForwarder(
        ArgPack< T01, T02 > const& args
        )
        : Base( args.a01, args.a02 )
    {}

    template< class T01, class T02, class T03 >
    ConstructorArgForwarder(
        ArgPack< T01, T02, T03 > const& args
        )
        : Base( args.a01, args.a02, args.a03 )
    {}

    // And more, up to max 12 arguments.
};

它依次使用参数包类 ArgPack(好吧,类模板),它看起来像这样:

enum NoArg {};

template<
    class T01 = NoArg, class T02 = NoArg, class T03 = NoArg,
    class T04 = NoArg, class T05 = NoArg, class T06 = NoArg,
    class T07 = NoArg, class T08 = NoArg, class T09 = NoArg,
    class T10 = NoArg, class T11 = NoArg, class T12 = NoArg
    >
struct ArgPack;

template<
    >
struct ArgPack<
    NoArg, NoArg, NoArg, NoArg, NoArg, NoArg,
    NoArg, NoArg, NoArg, NoArg, NoArg, NoArg
    >
{};

typedef ArgPack<
    NoArg, NoArg, NoArg, NoArg, NoArg, NoArg,
    NoArg, NoArg, NoArg, NoArg, NoArg, NoArg
    >                                           EmptyArgPack;

inline ArgPack<> args() { return ArgPack<>(); }

template<
    class T01
    >
struct ArgPack<
    T01, NoArg, NoArg, NoArg, NoArg, NoArg,
    NoArg, NoArg, NoArg, NoArg, NoArg, NoArg
    >
{
    T01 const&  a01;
    ArgPack( T01 const& v01 )
        : a01( v01 )
    {}
};

template< class T01 >
inline ArgPack< T01 >
args( T01 const& a01 )
{
    return ArgPack< T01 >( a01 );
}

免责声明:错误可能只是潜入,例如从我的博客复制代码。但是,它在我发布相关信息时有效,即 2010 年 5 月。

注意:正如我在上面两篇博文的最后一篇中所讨论的,关于克隆,有 三种 主要的通用方法,其中简单的 对于 C++03,以良好的优势击败其他两个。但是,对于 C++11,您在此处选择的“中间人”方法似乎更好。通过支配的“横向继承”只是复杂且效率低下,但如果你受限于 C++03,那么请考虑一个简单的宏!

注 2:上次我建议做实际和明智的事情时,我被严重否决了(大概是被 Reddit 的 children )。然而,从那时起,我就不再关心 SO 代表点数,尤其是反对票。所以,令人高兴的是,我现在可以再次提供好的建议,就像在旧的 Usenet 时代一样,只是忽略他们反对 child 对某些词的无意识 react 。 :-)

关于c++ - 带有 CRTP 的转发构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9520745/

相关文章:

c++ - 用 CRTP 替换非纯虚函数

c++ - 防止用户从不正确的 CRTP 基础派生

c++ - float 类型的默认参数 = 乱码

c++ - 如何用mingw在windows上编译rtaudio?

c++ - CRTP和模板模板?

javascript - 如何将一个 map 复制到另一个 map ?

javascript - 拖动时克隆节点

c++ - 在编译时或至少在使用之前检查字符串是否包含禁止字符的任何创造性方法?

c++ - TripleDes 会改变数据大小吗

java - BeanUtils.copyProperties 是否进行深度克隆?