Search code examples
c++c++11variadic-templatessfinae

conjunction type traits in C++11


I need to check variadic arguments in std::enable_if:

With C++17 I would write:

template <typename A, typename ...B>
class Foo : public A, public B...
{

public:

    template <typename = std::enable_if_t<std::is_default_constructible_v<A> &&
        (std::is_default_constructible_v<B> && ...)>>
    Foo()
    {}
    
    Foo(A &&a, B && ... b)
       : A(std::forward<A>(a)),
       B(std::forward<B>(b))...
    {}

};

But C++11 doesn't have a feature of expanding parameter packs this way. Neither does it provides std::conjunction.

What is a simple way to implement conjunction with C++11? I suppose SFINAE with recursion would suffice, but I cannot wrap my hand around it.


Solution

  • You need a tool which will do the conjunction operation on variadic arguments.

    #include <iostream>
    #include <type_traits>
    
    template<class...> struct conjunction : std::true_type { };
    template<class B1> struct conjunction<B1> : B1 { };
    template<class B1, class... Bn>
    struct conjunction<B1, Bn...> 
        : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
    
    template <typename A, typename ...B>
    class Foo : public A, public B...
    {
    
    public:
    
        template <typename std::enable_if<std::is_default_constructible<A>::value &&
            conjunction<std::is_default_constructible<B>...>::value, bool>::type = true>
        Foo()
        {}
        
        Foo(A &&a, B && ... b)
           : A(std::forward<A>(a)),
           B(std::forward<B>(b))...
        {}
    
    };
    
    struct A {};
    struct B {};
    struct C {
        C(int x) {}
    };
    
    int main()
    {
        Foo<A, B> foo;
        //Foo<A, B, C> bar;
    
        return 0;
    }
    

    https://godbolt.org/z/d3jvM4

    based on https://en.cppreference.com/w/cpp/types/conjunction which is available in C++17.