I'd create a helper. One of these may suite you:
template <class T, class... Ts>
concept HasOverloadForOneOf =
(... || requires { std::declval<T>().template f<Ts>(); });
template <class T, class... Ts>
concept HasOverloadForAllOf =
(... && requires { std::declval<T>().template f<Ts>(); });
Then defining HasValidF becomes a little simpler although you still have to list all the types that should be taken into consideration. If you want your type to have at least one matching overload, you'd use HasOverloadForOneOf. If you want it to have overloads for all, use HasOverloadForAllOf:
template <class T>
concept HasValidF =
HasOverloadForAllOf<T, bool, char, signed char, unsigned char, short,
unsigned short, int, unsigned, long, unsigned long,
long long, unsigned long long>;
Demo
If you want all const, volatile and const volatile versions too, you could either list them manually in HasOverloadForOneOf/HasOverloadForAllOf or add helpers to create them:
template <class...> struct make_const;
template <class... Ts>
struct make_const<std::tuple<Ts...>> {
using type = std::tuple<std::add_const_t<Ts>...>;
};
template <class T> using make_const_t = make_const<T>::type;
template <class...> struct make_volatile;
template <class... Ts>
struct make_volatile<std::tuple<Ts...>> {
using type = std::tuple<std::add_volatile_t<Ts>...>;
};
template <class T> using make_volatile_t = make_volatile<T>::type;
//------------------------------------------------------------------------------
using base_integrals = std::tuple<bool, char, signed char, unsigned char, short,
unsigned short, int, unsigned, long,
unsigned long, long long, unsigned long long>;
using all_integrals =
decltype(std::tuple_cat(base_integrals{},
make_const_t<base_integrals>{},
make_volatile_t<base_integrals>{},
make_const_t<make_volatile_t<base_integrals>>{}));
//------------------------------------------------------------------------------
template<class...> struct HasValidFHelper;
template<class T, class... Ts> struct HasValidFHelper<T, std::tuple<Ts...>> {
static constexpr bool value = HasOverloadForAllOf<T, Ts...>;
};
template <class T>
concept HasValidF = HasValidFHelper<T, all_integrals>::value;
Demo
struct B { template <typename T> void f(); };would be accepted with your definition ofHasValidF, which might not be what you want.HasValidF? I don't get it.HasValidFwill fail sincefdoesn't take any arguments.template <std::integral T> void f();should betemplate <std::integral T> void f(T)