简体   繁体   English

检查类是否是模板特化

[英]Check if class is a template specialization

I want to check if a class is a template specialization of another one.我想检查一个类是否是另一个类的模板特化。 What I have tried is:我尝试过的是:

template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};

template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};

It works fine when all template parameters are type arguments but not when some are non-type arguments .当所有模板参数都是类型参数时它工作得很好,但当一些是非类型参数时就不行了 For example it works with std::vector but not std::array (since the later accepts an non-type argument std::size_t ).例如,它适用于std::vector但不适用于std::array (因为后者接受非类型参数std::size_t )。

It's important that the check is made at compile time.在编译时进行检查很重要。 Also the solution must work for any template, not just vectors or arrays.此外,该解决方案必须适用于任何模板,而不仅仅是向量或数组。 That means that it can be any number of type arguments and any number of non-type arguments.这意味着它可以是任意数量的类型参数和任意数量的非类型参数。 For example it should work with template <class A, bool B, class C, int D, class... Args> class foo;例如它应该使用template <class A, bool B, class C, int D, class... Args> class foo;

C++20 is a weird, weird world. C++20 是一个奇怪的、奇怪的世界。 Cross-checking is welcome as I'm a beginner with CTAD and not entirely sure I've covered all bases.欢迎交叉检查,因为我是 CTAD 的初学者,并不完全确定我已经涵盖了所有基础。

This solution uses SFINAE to check whether class template argument deduction (CTAD) succeeds between the requested class template and the mystery type.该解决方案使用 SFINAE 来检查所请求的类模板和神秘类型之间的类模板参数推导 (CTAD) 是否成功。 An additional is_same check is performed to prevent against unwanted conversions.执行额外的is_same检查以防止不需要的转换。

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.第一个警告:由于我们不能在不知道参数的情况下以任何方式为类模板声明参数,因此只能通过跳过一些箍来将其传递到将执行 CTAD 的位置。 C++20 constexpr and template-friendly lambdas help a lot here, but the syntax is a mouthful, hence the helper macro. C++20 constexpr 和模板友好的 lambda 在这里有很大帮助,但语法很复杂,因此有帮助宏。

Second caveat: this only works with movable types, as CTAD only works on object declarations, not reference declarations.第二个警告:这只适用于可移动类型,因为 CTAD 仅适用于对象声明,而不适用于引用声明。 Maybe a future proposal will allow things such as std::array &arr = t;也许未来的提案将允许诸如std::array &arr = t;东西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!实际上是通过记住 C++17 保证复制省略来修复的,它允许从不可移动的右值直接初始化,就像这里的情况一样!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM