C++ 将实现注入到单个多功能接口类-多个CRTP类?

C++ 将实现注入到单个多功能接口类-多个CRTP类?,c++,interface,c++14,crtp,vtable,C++,Interface,C++14,Crtp,Vtable,如何创建多个类来充当接口类的实现者,同时尽可能避免v-table成本,并且仍然能够对接口进行静态转换 对于一个简单的情况,可以像下面的示例中那样实现 例子 库代码:- class I{ //interface public: virtual void i1()=0; }; template<class Derived>class Router : public I{ public: virtual void i1()final{ //in r

如何创建多个类来充当接口类的实现者,同时尽可能避免v-table成本,并且仍然能够对接口进行静态转换

对于一个简单的情况,可以像下面的示例中那样实现

例子 库代码:-

class I{ //interface
    public: virtual void i1()=0;
};
template<class Derived>class Router : public I{ 
    public: virtual void  i1()final{   
        //in real case it is very complex, but in the core is calling :-
        static_cast<Derived*>(this)->u1(); 
    }
};
class User : public Router<User>{
    public: void u1(){ std::cout<<"hi"<<std::endl; }
};
int main() {
    User u;
    u.i1();   //<-- no v-table cost
    I* i=&u;
    i->i1();  //<-- has v-table cost (OK)
}
class I{ //interface
    public: virtual void i1()=0;
    public: virtual void i2()=0;
};
template<class Derived>class RouterI1U1 : public I{ 
    public: virtual void  i1()final{ static_cast<Derived*>(this)->u1(); }
};
template<class Derived>class RouterI1U2 : public I{ 
    public: virtual void  i1()final{ static_cast<Derived*>(this)->u2(); }
};
template<class Derived>class RouterI2U1 : public I{ 
    public: virtual void  i2()final{ static_cast<Derived*>(this)->u1(); }
};
template<class Derived>class RouterI2U2 : public I{ 
    public: virtual void  i2()final{ static_cast<Derived*>(this)->u2(); }
};
我拙劣的解决方案
I类{//接口
public:虚空i1()=0;
public:virtualvoid i2()=0;
};
模板类RouterI1U2\u I2U1:公共I{//将其分组
public:virtualvoidi1()最终{static_cast(this)->u2();}
public:virtualvoid i2()final{static_cast(this)->u1();}
};
类用户:公共路由I1U22U1{

public:void u1(){std::cout使用虚拟继承

template<class Derived>class RouterI1U1 : public virtual I{ 
templateclass路由Iu1:公共虚拟I{

etc.使代码可编译。

它可能不适用于您的情况,但也可能对其他阅读问题的人有用

我建议您在这种特殊情况下使用概念模型习惯用法。其目的是将多态性实现和这些类本身的实现分离为不同的部分。在这里,
I
成为具有
i1
i2
成员函数的任何类的多态包装器:

class I {
    // The interface is internal, invisible to outside
    // We use this as a type erasure technique and polymorphism
    struct Concept {
        virtual void i1() = 0;
        virtual void i2() = 0;
    };

    // The single implementation that directly
    // extend the interface is the model. T is the user class.
    // T must have i1 and i2 function, because we call them.
    template<typename T>
    struct Model : Concept {

        // The user class.
        // If you want, you can use a reference there if you
        // need references semantics with I
        T user;

        Model (T u) : user{std::move(u)} {}

        // The only implementation of i1 is to call i1 from the user class
        void i1() override {
            user.i1();
        }

        void i2() override {
            user.i2();
        }
    };

    // Or use a shared, or use SBO
    std::unique_ptr<Concept> concept;

public:
    // When we make an I, we must provide a user class.
    // If the user class had i1 and i2, it will compile.
    // If Model takes a reference, use a reference there too.
    template<typename T>
    I(T model) : concept{std::make_unique<Model<T>>(std::move(model))} {}

    void i1() {
        concept->i1();
    }

    void i2() {
        concept->i2();
    }
};
如您所见,我们没有任何虚拟方法。多态性是
I
的一个实现细节。由于该类具有所有必需的成员函数,因此
I
类将允许它

使用类
I
也很简单。让
User2
成为另一个符合
I
要求的用户类:

User2 user2;

user2.i1(); // no vtable, so no vtable overhead possible

I myI{user2}; // works!

myI.i2(); // calls u2, with vtable

std::vector<I> v;

v.emplace_back(User2{});
v.emplace_back(User{}); // simple heh?
现在,如果
i1
i2
不存在,我们可以将模型实现更改为调用
u1
u2

template<typename T>
struct Model : Concept {
    T user;

    Model(T u) : user{std::move(u)} {}


    void i1() override {
        i1_helper(user);
    }

    void i2() override {
        i2_helper(user);
    }

private:
    template<typename U>
    auto i1_helper(U& u) -> std::enable_if_t<has_i1<U>::value> {
        // Call i1 if has i1
        u.i1();
    }

    template<typename U>
    auto i1_helper(U& u) -> std::enable_if_t<!has_i1<U>::value> {
        // Call u1 if has not i1
        u.u1();
    }

    template<typename U>
    auto i2_helper(U& u) -> std::enable_if_t<has_i2<U>::value> {
        // Call i2 if has i2
        u.i2();
    }

    template<typename U>
    auto i2_helper(U& u) -> std::enable_if_t<!has_i2<U>::value> {
        // Call u2 if has not i2
        u.u2();
    }
};

它能工作()…将
u.i1();
仍然不会承受v-table成本,而
i->i1();
将承受相同水平的v-table成本?(赞扬伟大的n.m.)哦,这样,我就不能
User*uPtr=static\u cast(i)
…不过我从来没有说过我想要它。我可能不需要它。:)是的,你需要一个动态演员阵容。至于成本,我相信u.i1()仍然不会产生可变成本,而我->i1()可能会因为砰的一声而导致稍高的成本。确实很有趣。使用这种方法,多重继承非常干净。我觉得它就像手工制作一个自定义虚拟继承,因此更可控。所有脏作业都移动到一个地方,因此更易维护。Thank.CRTP也非常灵活,这不是您的o只有一个选项。如果我没记错的话,有几种方法可以绕过所有的
void i1(){static_cast(this)->u1();}
重复。在我的活动项目中,我有
bool更新(updateable&u)
调用
static\u cast
-ed u的
update
方法,而
updateable
只是实现
update()的承诺
。如果不遵守该承诺,则会导致替换失败,您可以决定默认候选项或编译器错误是否更合适。一旦得到它,请尝试嵌套/链接/
公共类型
/等等!
template<class Derived>
struct RouterI1U1 { // no Inheritance needed
    void i1() { static_cast<Derived*>(this)->u1(); }
};

template<class Derived>
struct RouterI1U2 { 
    void i1() { static_cast<Derived*>(this)->u2(); }
};

template<class Derived>
struct RouterI2U1 { 
    void i2() { static_cast<Derived*>(this)->u1(); }
};

template<class Derived>
struct RouterI2U2 { 
    void i2() { static_cast<Derived*>(this)->u2(); }
};
struct User : RouterI2U2<User> {
    void i1() {}
    void u2() {}
};
User2 user2;

user2.i1(); // no vtable, so no vtable overhead possible

I myI{user2}; // works!

myI.i2(); // calls u2, with vtable

std::vector<I> v;

v.emplace_back(User2{});
v.emplace_back(User{}); // simple heh?
template<typename...>
using void_t = void;

template<typename, typename>
struct has_i1 : std::false_type {};

template<typename T>
struct has_i1<T, void_t<decltype(std::declval<T>().i1())>> : std::true_type {};

template<typename, typename>
struct has_i2 : std::false_type {};

template<typename T>
struct has_i2<T, void_t<decltype(std::declval<T>().i2())>> : std::true_type {};
template<typename T>
struct Model : Concept {
    T user;

    Model(T u) : user{std::move(u)} {}


    void i1() override {
        i1_helper(user);
    }

    void i2() override {
        i2_helper(user);
    }

private:
    template<typename U>
    auto i1_helper(U& u) -> std::enable_if_t<has_i1<U>::value> {
        // Call i1 if has i1
        u.i1();
    }

    template<typename U>
    auto i1_helper(U& u) -> std::enable_if_t<!has_i1<U>::value> {
        // Call u1 if has not i1
        u.u1();
    }

    template<typename U>
    auto i2_helper(U& u) -> std::enable_if_t<has_i2<U>::value> {
        // Call i2 if has i2
        u.i2();
    }

    template<typename U>
    auto i2_helper(U& u) -> std::enable_if_t<!has_i2<U>::value> {
        // Call u2 if has not i2
        u.u2();
    }
};
struct User1 {
    void i1() {}
    void i2() {}
};

struct User2 {
    void i1() {}
    void u2() {}
};

struct User3 {
    void u1() {}
    void i2() {}
};

 struct User4 {
    void u1() {}
    void u2() {}
};