jeudi 21 juin 2018

Interdependent class template

I am mildy confused by the following situation where I have a specialization enabled on is_base_of.

is_base_of requires the full definition of the type that is being checked to be available. However, the type that is being specialized is being used as a member of the type who's base is being checked - so both need to be defined before the other, and I cannot forward declare the inheritance relationship.

What is confusing is that if I instead tag the base and enable on this tag existing, it works. Surely for this to work, the inheritance relationship must be known at this point. so why doesn't is_base_of work without the full definition being available?

#define OPTION 1 // OPTION 2 : broken, OPTION 1 : works

#include <iostream>
#include <type_traits>
using namespace std;


template <typename body_type,typename Enable=void>
struct limb
{
     const char* value = "regular limb";
};


template <typename SomeT>
struct body
{
    typedef SomeT type; 
    #if OPTION ==1
    struct body_tag{};

    #endif

};


#if OPTION ==2
template <typename body_type>
struct limb < body_type, typename std::enable_if < std::is_base_of< body<typename body_type::type>, body_type>::value>::type>
{

     const char* value = "fat limb";
};
#else

template <typename body_type>
struct limb < body_type, std::void_t<typename body_type::body_tag> >
{

     const char* value = "fat limb";
};

#endif



template <typename SomeT>
struct fatbody : body<SomeT>
{
        limb<fatbody> arm;
        typedef SomeT type; 
};

template <typename SomeT>
struct slimbody
{
        limb<slimbody> arm;
        typedef SomeT type; 
};



int main() {



    #if OPTION == 1
    // to check the enable cond used on OPTION 2 is correct
    typedef fatbody<int> body_type;
    typedef slimbody<int> body_type2;
    std::cout << std::is_base_of<body<typename body_type::type>,body_type >::value << std::endl;
    std::cout << std::is_base_of<body<typename body_type2::type>,body_type2 >::value << std::endl;
    #endif

    std::cout << slimbody<int>().arm.value << std::endl;
    std::cout << fatbody<int>().arm.value << std::endl;
    return 0;
}

EXAMPLE

Aucun commentaire:

Enregistrer un commentaire