I am looking for a way to use SFINAE to implement some function, that must be available only to some containers: vector, list, array (set is there below only as a test)
Build upon this answer, I tried the code below that uses a traits class that returns true only for the required containers.
As you can see online here, it fails for std::array
.
template <typename Container>
struct is_container : std::false_type { };
template <typename... Ts> struct is_container<std::array<Ts... >> : std::true_type { };
template <typename... Ts> struct is_container<std::vector<Ts...>> : std::true_type { };
template <typename... Ts> struct is_container<std::set<Ts... >> : std::true_type { };
template <typename... Ts> struct is_container<std::list<Ts... >> : std::true_type { };
template <typename... Ts> struct Dummy{};
int main()
{
std::cout << "Dummy: " << is_container<Dummy<int>>::value << '\n';
std::cout << "array: " << is_container<std::array<int,5>>::value << '\n';
std::cout << "vector:" << is_container<std::vector<int>>::value << '\n';
std::cout << "set: " << is_container<std::set<int>>::value << '\n';
std::cout << "list: " << is_container<std::list<int>>::value << '\n';
}
What I understand is that this is due to the fact that std::array
requires a second template parameter.
I have a low experience with variadic templates, so my question is:
Is there a way to make this approach successful? Or shall I use another approach described in the linked question?
I'd rather have something pure C++11, but C++14 would be ok too.
Substitution failure is not an error (SFINAE) refers to a situation in C++ where an invalid substitution of template parameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.
template <typename T> ... This means exactly the same thing as the previous instance. The typename and class keywords can be used interchangeably to state that a template parameter is a type variable (as opposed to a non-type template parameter).
Only the failures in the types and expressions in the immediate context of the function type or its template parameter types or its explicit specifier (since C++20) are SFINAE errors.
SFINAE in partial specializations Deduction and substitution also occur while determining whether a specialization of a class or variable (since C++14) template is generated by some partial specialization or the primary template.
Where applicable, tag dispatch, if constexpr (since C++17), and concepts (since C++20) are usually preferred over use of SFINAE. static_assert is usually preferred over SFINAE if only a conditional compile time error is wanted.
In addition, many type traits must be implemented with SFINAE if appropriate compiler extensions are unavailable. The standard library component std::void_t is another utility metafunction that simplifies partial specialization SFINAE applications.
This is not SFINAE but regular template specialisation. Your std::array is not recognised because a value of type std::size_t (which ist std::array's second argument) is not a typename.
You can change your check for array specifically:
template <typename T, std::size_t N> struct is_container<std::array<T,N>> : std::true_type { };
template <typename... Ts> struct is_container<std::vector<Ts...>> : std::true_type { };
If you actually want to use SFINAE to check for anything that behaves like a container, you could check for the existance of std::begin, std::end, std::size for that type.
The problem is that the 2nd template parameter of std::array
is a non-type template parameter, which doesn't match type template parameter pack typename... Ts
.
You can change the specialization for std::array
to:
template <typename T, std::size_t S> struct is_container<std::array<T, S>> : std::true_type { };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With