C++20 is a weird, weird world. Cross-checking is welcome as I'm a beginner with CTAD and not entirely sure I've covered all bases.
This solution uses SFINAE to check whether class template argument deduction (CTAD) succeeds between the requested class template and the mystery type. An additional is_same
check is performed to prevent against unwanted conversions.
template <auto f>
struct is_specialization_of {
private:
template <class T>
static auto value_impl(int) -> std::is_same<T, decltype(f.template operator()<T>())>;
template <class T>
static auto value_impl(...) -> std::false_type;
public:
template <class T>
static constexpr bool value = decltype(value_impl<T>(0))::value;
};
// To replace std::declval which yields T&&
template <class T>
T declrval();
#define is_specialization_of(...)
is_specialization_of<[]<class T>() -> decltype(__VA_ARGS__(declrval<T>())) { }>::value
// Usage
static_assert(is_specialization_of(std::array)<std::array<int, 4>>);
First caveat: Since we can't declare a parameter for the class template in any way without knowing its arguments, passing it around to where CTAD will be performed can only be done by jumping through some hoops. C++20 constexpr and template-friendly lambdas help a lot here, but the syntax is a mouthful, hence the helper macro.
Second caveat: this only works with movable types, as CTAD only works on object declarations, not reference declarations. Maybe a future proposal will allow things such as std::array &arr = t;
, and then this will be fixed!
Actually fixed by remembering that C++17 has guaranteed copy-elision, which allows direct-initialization from a non-movable rvalue as is the case here!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…