How to achieve Conjunction of type traits

Viewed 69
template <typename T, typename... Tc>
constexpr bool ConjuctionofConvertible () noexcept
{
    return std::conjunction<std::is_convertible_v<T, Tc>...>::value;
}

Getting error:

Error   no return statement in constexpr function   
Error   template argument for template type parameter must be a type    
2 Answers

You just need to use is_convertible instead of the helper variable is_convertible_v:

template <typename T, typename... Tc>
constexpr bool ConjuctionofConvertible () noexcept
{
    return std::conjunction<std::is_convertible<T, Tc>...>::value;
}

or

template <typename T, typename... Tc>
constexpr bool ConjuctionofConvertible () noexcept
{
    return std::conjunction_v<std::is_convertible<T, Tc>...>;
}

See this possible implementation of conjunction:

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_t<bool(B1::value), conjunction<Bn...>, B1> {};
                              ^^^^^^^^^

You'll notice that it requires a type (with a value member), not a bool.


Other interesting notes, copied and edited from std::conjuction:

std::conjunction was added in C++17 and so was fold expressions. One reason for using conjuction over a fold expression is that conjunction is short-circuiting.

If there is a template type argument Bi with bool(Bi::value) == false, then instantiating conjunction<B1, ..., BN>::value does not require the instantiation of Bj::value for j > i.

The short-circuit instantiation differentiates conjunction from fold expressions: a fold expression like (... && Bs::value) instantiates every B in Bs, while std::conjunction_v<Bs...> stops instantiation once the value can be determined. This is particularly useful if the later type is expensive to instantiate or can cause a hard error when instantiated with the wrong type.

There is no need to use std::conjunction in your example, a simple fold-expression should be enough.

#include <type_traits>

template <typename T, typename... Tc>
constexpr bool AllConvertible () noexcept {
  return (std::is_convertible_v<T, Tc> && ...);
}
Related