C++ C++;概念:检查模板实例化

C++ C++;概念:检查模板实例化,c++,c++-concepts,c++20,clang,gcc,C++,C++ Concepts,C++20,Clang,Gcc,假设我有一个模板类型,例如 template<typename A, typename B, typename C> struct mytype { }; 模板 结构mytype{}; 如何编写一个概念来检查某个类型是否是该模板的实例化 template<typename T> concept MyType = requires(T x) { ??? } 模板 概念MyType=需要(T x){???} 我想不出一个明显的方法来做到这一点,而不解决旧式的专门探测器

假设我有一个模板类型,例如

template<typename A, typename B, typename C>
struct mytype { };
模板
结构mytype{};
如何编写一个概念来检查某个类型是否是该模板的实例化

template<typename T>
concept MyType = requires(T x) { ??? }
模板
概念MyType=需要(T x){???}

我想不出一个明显的方法来做到这一点,而不解决旧式的专门探测器类型,或者可能是标记基类型

您可以为此定义自己的元功能(类型特征):

template <typename T>
struct is_mytype : std::false_type { };

template <typename A, typename B, typename C>
struct is_mytype<mytype<A, B, C>> : std::true_type { };

template <typename T>
concept MyType = is_mytype<T>::value;
模板
结构是_mytype:std::false _type{};
模板
结构是_mytype:std::true _type{};
模板
概念MyType=is_MyType::value;

但是说实话,我不知道是否有一种方法可以直接定义这样一个概念,而不需要单独的元函数。

使用C++17类模板参数推断,您应该能够执行以下操作:

template<typename A, typename B, typename C>
struct mytype { };

template<class T>
concept C1 = requires(T x) { 
    { mytype{x} } -> std::same_as<T>;
};
检查
T
是否也是构建的
mytype
实例化避免匹配其他扣减指南,例如,这将匹配没有
->std::same的任何类型:

模板
结构mytype{
mytype(A);
};
模板
mytype(A)->mytype实验概念实现:
  • 当前实施(不符合标准):

  • 您可以编写一个通用特征来检查专业化:

    template <typename T, template <typename...> class Z>
    struct is_specialization_of : std::false_type {};
    
    template <typename... Args, template <typename...> class Z>
    struct is_specialization_of<Z<Args...>, Z> : std::true_type {};
    
    template <typename T, template <typename...> class Z>
    inline constexpr bool is_specialization_of_v = is_specialization_of<T,Z>::value;
    
    模板
    结构是:std::false类型{}的{u专门化};
    模板
    结构是:std::true类型{}的{u专门化};
    模板
    inline constexpr bool是v的专门化,是::value的专门化;
    
    您可以将其转化为广义概念:

    template<typename T, template <typename...> class Z>
    concept Specializes = is_specialization_of_v<T, Z>;
    
    template<typename T>
    concept MyType = Specializes<T, mytype>;
    
    模板
    概念专门化=是v的专门化;
    模板
    概念MyType=1;
    
    或者只是一个专门的:

    template<typename T>
    concept MyType = is_specialization_of_v<T, mytype>;
    
    模板
    概念MyType=是v的专业化;
    
    如果给模板类一些特性,可以执行以下操作:

    template<typename A, typename B, typename C>
    struct mytype {
        using a_type = A;
        using b_type = B;
        using c_type = C;
    };
    
    模板
    结构mytype{
    使用a_类型=a;
    使用b_type=b;
    使用c_type=c;
    };
    
    与联想概念:

    template <typename T>
    concept is_mytype =
        std::is_same_v<
            std::remove_const_t<T>,
            mytype<typename T::a_type, typename T::b_type, typename T::c_type>>;
    
    template <typename T>
    concept is_mytype =
        std::is_same_v<
            std::remove_const_t<T>,
            mytype<decltype(T::a_inst), decltype(T::b_inst), decltype(T::c_inst)>>;
    
    模板
    概念是我的类型=
    std::是相同的吗<
    标准::移除常数,
    mytype>;
    
    或者,如果mytype具有这些类型的成员,则可以跳过以下特征:

    template<typename A, typename B, typename C>
    struct mytype {
        A a_inst;
        B b_inst;
        C c_inst;
    };
    
    模板
    结构mytype{
    研究所;
    B_inst;
    中央研究所;
    };
    
    给出概念:

    template <typename T>
    concept is_mytype =
        std::is_same_v<
            std::remove_const_t<T>,
            mytype<typename T::a_type, typename T::b_type, typename T::c_type>>;
    
    template <typename T>
    concept is_mytype =
        std::is_same_v<
            std::remove_const_t<T>,
            mytype<decltype(T::a_inst), decltype(T::b_inst), decltype(T::c_inst)>>;
    
    模板
    概念是我的类型=
    std::是相同的吗<
    标准::移除常数,
    mytype>;
    
    为了简洁起见:

    template<typename T>
    concept MyType = requires(T** x) {
        []<typename A, typename B, typename C>(mytype<A, B, C>**){}(x);
    };
    

    目前,这只适用于gcc。

    不确定您到底在问什么。概念还没有出现在标准中,或者我错过了吗?它们出现在草案C++20中,所以我的问题当然是基于当前的草案,这有什么用?@cpplearner这样的用例之一可能只适用于特定类型的参数。比SFINAE更好的概念:)@cpplearner直接而明显的用途是强制执行类型安全,而不必经历通常冗长的模板舞。也就是说,您可以只执行
    template do_stuff(T)
    ,而不是
    template void do_stuff(mytype)
    。希望有一天能像斯特劳斯塔普所设想的那样,做一些事情(MyType T)
    。是的,这也是我的解决方案。我希望这些概念能让这种探测器过时。@Mobster先生,确实如此。。。一旦你写好了。呵呵。但是谁说A、B和C可以这样推断呢?@einpoklum总是隐式生成的。即使有(隐式)删除的复制构造函数,本指南也存在,但在这种情况下,该概念将失败(在我的回答中指定)。您的意思是,一个将设法推断,B和C完全适用于模板的实例化类型T?我不知道为什么有人会否决你的答案-这是正确的,并且准确地回答了我的问题。@einpoklum假设
    mytype
    有一个未删除的副本构造函数,你有一个隐式生成的演绎指南,类似于:
    template mystruct(mystruct const&)->mystruct;
    ,这是副本演绎指南。它并不是真正的泛化,因为它只适用于本身采用类型的模板类。所以你不能问它是否是
    std::array
    或甚至
    std::span
    的特化,因为它们采用非类型模板参数。@Nicolas大多数模板只采用类型参数。@Nicolaspe参数。所以我想说它是相当通用的。但是,是的,它对这两个参数不起作用。太棒了,谢谢!我使用了最后一个参数,但只有单指针,因为我希望能够检测模板类型的派生类。这减少了14行代码。\o/
    template<class T> constexpr auto L = []<typename A, typename B, typename C>(mytype<A, B, C>**){};
    template<typename T>
    concept MyType = requires(T** x) { L<T>(x); };
    
    template<typename T>
    concept MyType = requires(T** x) { [](mytype<auto, auto, auto>**){}(x); };