Home > Software design >  type 'X' is not a direct type of 'Y' - but with std::conditional
type 'X' is not a direct type of 'Y' - but with std::conditional

Time:07-13

I have a Base class, two classes inheriting from that base class (they are slightly different from each other) and a Last class which can either inherit from Derived1 or Derived2 based on a template. I use std::conditional to determine at compile time which DerivedX it should actually use:

template< class >
class Base;

template< class T, class ...Args >
class Base < T(Args...) >
{
public:
    Base(int a) { std::cout << "Base constructor " << a << std::endl; }
};

template< class >
class Derived1;

template< class ...Args >
class Derived1 < void(Args...) > : public Base< void(Args...) >
{
public:
    Derived1(int a) : Base< void(Args...) >(a)
        { std::cout << "Derived1 constructor " << a << std::endl; }
};

template< class >
class Derived2;

template< class T, class ...Args >
class Derived2 < T(Args...) > : public Base< T(Args...) >
{
public:
    Derived2(int a) : Base< T(Args...) >(a)
        { std::cout << "Derived2 constructor " << a << std::endl; }
};

template< class >
class Last;

template< class T, class ...Args >
class Last< T(Args...) > : public std::conditional<
    std::is_void<T>::value,
    Derived1< void(Args...) >,
    Derived2< T(Args...) > >
{
public:
    Last(int a) : std::conditional<
        std::is_void<T>::value,
        Derived1< void(Args...) >,
        Derived2< T(Args...) > >::type(a)
    { std::cout << "Last constructor " << a << std::endl; }
};

int main()
{
    Last<int(int)> last(1);

    return 0;
}

I have read multiple topics about diamond heritage and virtual inheritance and I get the same error as those topics: type Derived2<...> is not a base class of Last<...>. However these topics never use an std::conditional. Btw it compiled fine until I try to instantiate a Last object. Is there something I'm missing ? Is it even possible to do it like that ?

CodePudding user response:

In your declaration of the base class:

template< class T, class ...Args >
class Last< T(Args...) > : public std::conditional<
    std::is_void<T>::value,
    Derived1< void(Args...) >,
    Derived2< T(Args...) > >
{
...
}

You either need to say public std::conditional_t (where the _t is very important at the end), or else you need to put ::type after the std::conditional template parameters, as in the following:

template< class T, class ...Args >
class Last< T(Args...) > : public std::conditional<
    std::is_void<T>::value,
    Derived1< void(Args...) >,
    Derived2< T(Args...) > >::type
{
...
}

Otherwise, your base type is std::conditional and you are trying to mem-initialize Derived2, which is not the same type.

  • Related