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.