Since C++ 17, we can use the variadic template class std::void_t
to implement class specialization. Typically, it is used to detect whether a type supports some map of type.
Example: remove_all_extents for array-like types
#include <type_traits>
#include <utility>
template <typename T, typename = void>
struct remove_all_extents {
typedef std::remove_reference_t<T> type;
};
template <typename T>
struct remove_all_extents<T, std::void_t<decltype(std::declval<T>()[0])>> {
typedef typename remove_all_extents<decltype(std::declval<T>()[0])>::type type;
};
#include <vector>
#include <iostream>
int main() {
std::cout << std::boolalpha;
std::cout << std::is_same_v<remove_all_extents<int[10]>::type, int> << "
";
std::cout << std::is_same_v<remove_all_extents<double[10]>::type, double> << "
";
std::cout << std::is_same_v<remove_all_extents<std::vector<int>>::type, int> << "
";
using v2 = std::vector<std::vector<int>>;
std::cout << std::is_same_v<remove_all_extents<v2>::type,int> << "
";
}
https://godbolt.org/z/hvG3chYfx
std::void_t
is used here to detect whether the given type T
supports the subscript operator.