Lately i tried to write wrapper arount void_t idiom simple as following:
namespace detail {
template <class Traits, class = void>
struct applicable : std::false_type {};
template <class... Traits>
struct applicable<std::tuple<Traits...>, std::void_t<Traits...>>
: std::true_type {};
} // namespace detail
template <class... Traits>
using applicable = detail::applicable<Traits...>;
and something like than on the call side
template <class T>
using call_foo = decltype(std::declval<T>().foo());
template <class T>
using has_foo = applicable<call_foo<T>>;
auto main() -> int {
std::cout << std::boolalpha << has_foo<std::vector<int>>::value;
}
but insted of expected "false" i get compile-time error:
error: 'class std::vector<int, std::allocator<int> >' has no member named 'foo'
using has_foo = my::applicable<call_foo<T>>;
What is wrong?
Update: The idea behind using parameter pack in traits is to use this applicable metafunction as follows:
template <class T>
using call_foo = decltype(std::declval<T>().foo());
template <class T>
using call_boo = decltype(std::declval<T>().boo());
template <class T>
using call_bar = decltype(std::declval<T>().bar());
template <class T>
using has_foo_and_boo_and_bar = applicable<call_foo<T>, call_boo<T>, call_bar<T>>;
The key here is not to apply trait onto multiple classes but to apply multiple traits onto one class without the use of std::conjunction.
Something like that :
https://godbolt.org/z/rzqY7G9ed
You probably can write all in one go, but I separate each part. I found it easier to understand when I go back on my code later on.
Note:
In your update you want:
It's impossible.
applicable<int, ERROR_TYPE>will not compile. It's not a "substitution error" it is an error.You have 2 options (AFAIK)
applicable<traits_foo<T>::value, traits_bar<T>::value>. Note thevalue. In this case each type trait will tell if a property is respected andapplicablewill just check that all boolean are true.type_traits<T>but justtype_traits) and the type to check and use SFINAE in applicable. That what I have done below.With the same principle, we can create a "list of template class". On this implementation, we expect a type traits to have a
::valuethat why I passhas_bar_oneand notcall_barhttps://godbolt.org/z/K77o3KxTj
Or just use Boost::Hana
https://godbolt.org/z/aM5YT8a56