What would a CRTP-based solution to this look like?

前端 未结 2 776
南笙
南笙 2020-12-22 01:49

I asked the following question in this post (pasted below for convenience). One of the comments suggested that there is a CRTP-based solution to the problem. I am not able t

相关标签:
2条回答
  • 2020-12-22 02:27

    to know whether a class derives from a base class we have the std::is_base_of<> template structure, which can be used in conjunction with partial specialisation, or std::enable_if.

    Here is a demonstration of using a partially specialised structure to apply a an operation depending on whether it's derived from node_base or not (in this case, it just prints the base object but you could do any other operation)

    #include <iostream>
    #include <type_traits>
    
    // base class
    struct node_base
    {
    
    };
    
    std::ostream& operator<<(std::ostream& os, const node_base& nb)
    {
        os << "node_base_stuff";
        return os;
    }
    
    // a class derived from node_base
    struct node : public node_base
    {
    
    };
    
    // a class not derived from node_base    
    struct not_node
    {
    
    };
    
    // apply the general case - do nothing
    template<class T, class = void>
    struct report_impl
    {
        static void apply(const T&) {};
    };
    
    // apply the case where an object T is derived from node_base    
    template<class T>
    struct report_impl<T, std::enable_if_t< std::is_base_of<node_base, T>::value > >
    {
        static void apply(const T& t) {
            std::cout << static_cast<const node_base&>(t) << std::endl;
        };
    };
    
    // the general form of the report function defers to the partially
    // specialised application class
    template<class T>
    void report(const T& t)
    {
        report_impl<T>::apply(t);
    }
    
    using namespace std;
    
    // a quick test    
    auto main() -> int
    {
        node n;
        not_node nn;
        report(n);
        report(nn);
    
        return 0;
    }
    

    expected output:

    node_base_stuff
    
    0 讨论(0)
  • 2020-12-22 02:35

    Here is my own first solution. It is not CRTP though and it suffers from a huge drawback as explained at the end of the answer:

    template <class Base1_ = void, class Base2_ = void, class Base3_ = void,
              class Base4_ = void>
    struct ManagedNode;
    
    // For classes that do not derive
    template <> struct ManagedNode<void, void, void, void> {
        using Base1 = void; using Base2 = void; using Base3 = void;
        using Base4 = void;
    };
    // To avoid inaccessible base
    // See http://stackoverflow.com/q/34255802/2725810
    struct Inter0: public ManagedNode<>{};
    
    // For classes that derive from a single base class
    template <class Base1_>
    struct ManagedNode<Base1_, void, void, void> : public Inter0,
                                                   public Base1_ {
        using Base1 = Base1_;
    };
    // To avoid inaccessible base
    template <class Base1_>
    struct Inter1: public ManagedNode<Base1_>{};
    
    // For classes that derive from two base classes
    template <class Base1_, class Base2_>
    struct ManagedNode<Base1_, Base2_, void, void> : public Inter1<Base1_>,
                                                     public Base2_ {
        using Base2 = Base2_;
    };
    
    // Some user classes for testing the concept
    
    struct A : public ManagedNode<> {
        int data1;
    };
    
    struct B : public ManagedNode<> {};
    
    struct C : public ManagedNode<A, B> {};
    
    int main() {
        C c;
        std::cout << sizeof(c) << std::endl;
        return 0;
    }
    

    This code produces the output of 12, which means that c contains the data1 member three times! For my purposes this drawback over-weighs the benefits of the reflection that this approach provides. So, does anyone have a suggestion for a better approach?

    0 讨论(0)
提交回复
热议问题