C++ 如何检查函数中的模板参数是否与给定类型别名的专门化匹配

C++ 如何检查函数中的模板参数是否与给定类型别名的专门化匹配,c++,templates,variadic-templates,c++17,type-alias,C++,Templates,Variadic Templates,C++17,Type Alias,我有以下代码: template <template <class...> class Temp, class Specialization> struct IsSpecialization : std::false_type {}; template <template <typename...> class Temp1, template <typename...> class Temp2, typename...

我有以下代码:

template <template <class...> class Temp, class Specialization>
struct IsSpecialization : std::false_type {};


template <template <typename...> class Temp1,
          template <typename...> class Temp2, typename... Ts>
struct IsSpecialization<Temp1, Temp2<Ts...>>
    : std::is_same<Temp1<Ts...>, Temp2<Ts...>> {};

struct ExprKindMerge {};
struct ExprKindSequence {};

template <class Tag, class... Args>
struct Expr {
    std::tuple<Args...> tup;

    constexpr std::tuple<Args...> toStdTuple() const {
        return this->tup;
    }

    constexpr std::size_t size() const noexcept {
        return std::tuple_size<decltype(tup)>{};
    }
};

template <class...Args>
using MergeExpr = Expr<ExprKindMerge, Args...>;

template <class...Args>
using SequenceExpr = Expr<ExprKindSequence, Args...>;
模板
结构IsSpecialization:std::false_type{};
模板
结构专业化
:std::是相同的{};
结构ExprKindMerge{};
结构ExprKindSequence{};
模板
结构表达式{
std::tuple-tup;
constexpr std::tuple tostduple()const{
返回此->tup;
}
constexpr std::size\u t size()const noexcept{
返回std::tuple_size{};
}
};
模板
使用mergexpr=Expr;
模板
使用SequenceExpr=Expr;
此函数有时接收一个
sequencexpr
作为模板参数:

template <class FullExpr>
auto f(FullExpr expr) {
    ///**************THIS RETURNS FALSE I EXPECT TRUE
    ///Type of full expr is Expr<ExprKindSequence, ...> which is
    /// the expansion of SequenceExpr<...>
    if constexpr (IsSpecialization<SequenceExpr, FullExpr>::value) 
    //...
}
模板
自动f(FullExpr expr){
///**************这返回FALSE,我希望返回TRUE
///完整expr的类型是expr,它是
///SequenceExpr的扩展
if constexpr(IsSpecialization::value)
//...
}

我希望能够检测
FullExpr
是否是
SequenceExpr
的专门化,但由于未知原因失败。

如果您只对
SequenceExpr
的专门化感兴趣,请,我能想象的最好的方法是添加一个专门化
IsSpecialization
,定义如下

template <typename... Ts>
struct IsSpecialization<SequenceExpr, Expr<ExprKindSequence, Ts...>>
    : std::true_type
 { };
的专门化是上述匹配的专门化
,您将得到
true
;我不知道你到底想要什么

下面是一个完整的工作示例

#include <tuple>
#include <iostream>
#include <type_traits>

template <template <typename...> typename Temp, typename Specialization>
struct IsSpecialization : std::false_type
 { };

template <template <typename...> class Temp1,
          template <typename...> class Temp2, typename... Ts>
struct IsSpecialization<Temp1, Temp2<Ts...>>
    : std::is_same<Temp1<Ts...>, Temp2<Ts...>>
 { };

struct ExprKindMerge {};
struct ExprKindSequence {};

template <typename Tag, typename... Args>
struct Expr
 {
    std::tuple<Args...> tup;

    constexpr std::tuple<Args...> toStdTuple () const
     { return this->tup; }

    constexpr std::size_t size () const noexcept
     { return std::tuple_size<decltype(tup)>{}; }
 };

template <typename ... Args>
using MergeExpr = Expr<ExprKindMerge, Args...>;

template <typename ... Args>
using SequenceExpr = Expr<ExprKindSequence, Args...>;

template <typename ... Ts>
struct IsSpecialization<SequenceExpr, Expr<ExprKindSequence, Ts...>>
    : std::true_type
 { };

template <class FE>
auto f (FE expr)
 { std::cout << IsSpecialization<SequenceExpr, FE>::value << std::endl; }

int main ()
 {
   f(SequenceExpr<int, long>{});             // print 1
   f(Expr<ExprKindSequence, int, long>{});   // print 1  (?)
   f(Expr<int, long>{});                     // print 0
   f(int{});                                 // print 0
 }
#包括
#包括
#包括
模板
结构IsSpecialization:std::false\u类型
{ };
模板
结构专业化
:std::是否相同
{ };
结构ExprKindMerge{};
结构ExprKindSequence{};
模板
结构表达式
{
std::tuple-tup;
constexpr std::tuple tostduple()const
{返回此->tup;}
constexpr std::size\u t size()const noexcept
{return std::tuple_size{};}
};
模板
使用mergexpr=Expr;
模板
使用SequenceExpr=Expr;
模板
结构专业化
:std::true\u类型
{ };
模板
自动f(FE expr)

{std::cout失败的原因很简单。对于
SequenceExpr
Temp2
被推断为
Expr
Ts.
被推断为
ExprKindSequence,extrargs…
。然后
Temp1
被推断为
Expr
,显然与
Temp2
不同

我知道没有完全通用的方法可以做到这一点。毕竟,对于
IsSpecialization
,这样一个假设的模板可能需要返回
true

如果我们将其限制为在可推断上下文中使用其参数的别名模板(在您的示例中就是这种情况),那么一种可能的方法是问这样一个问题:“我可以从
专门化
中推断
Ts.
中的
Temp
?”:

名称空间详细信息{
模板类类型{};
模板
无效推导出(类型);
}
模板
结构IsSpecialization:std::false_type{};
模板
结构专业化
:std::true_type{};
静态断言(IsSpecialization());
静态断言(IsSpecialization());
静态断言(!IsSpecialization());
静态断言(!IsSpecialization());

但您感兴趣的是单一类型traits
IsSpecialization
,它可以检测一个类型是泛型容器的专门化,还是只检查
SequenceExpr
(可能还有一个很短的别名列表)?@max66我想知道我的函数在顶级FullExpr接收的是不是SequenceExpr。SequenceExpr是Expr的别名。“它因未知原因失败”-它到底是如何失败的?@Edgarokyan我以前更改过。可能还没有刷新,请等待几分钟再刷新。@VTT true。无论如何,这不是本文的要点。事实上,我正在做一些稍微不同的事情,但这可以作为说明。
#include <tuple>
#include <iostream>
#include <type_traits>

template <template <typename...> typename Temp, typename Specialization>
struct IsSpecialization : std::false_type
 { };

template <template <typename...> class Temp1,
          template <typename...> class Temp2, typename... Ts>
struct IsSpecialization<Temp1, Temp2<Ts...>>
    : std::is_same<Temp1<Ts...>, Temp2<Ts...>>
 { };

struct ExprKindMerge {};
struct ExprKindSequence {};

template <typename Tag, typename... Args>
struct Expr
 {
    std::tuple<Args...> tup;

    constexpr std::tuple<Args...> toStdTuple () const
     { return this->tup; }

    constexpr std::size_t size () const noexcept
     { return std::tuple_size<decltype(tup)>{}; }
 };

template <typename ... Args>
using MergeExpr = Expr<ExprKindMerge, Args...>;

template <typename ... Args>
using SequenceExpr = Expr<ExprKindSequence, Args...>;

template <typename ... Ts>
struct IsSpecialization<SequenceExpr, Expr<ExprKindSequence, Ts...>>
    : std::true_type
 { };

template <class FE>
auto f (FE expr)
 { std::cout << IsSpecialization<SequenceExpr, FE>::value << std::endl; }

int main ()
 {
   f(SequenceExpr<int, long>{});             // print 1
   f(Expr<ExprKindSequence, int, long>{});   // print 1  (?)
   f(Expr<int, long>{});                     // print 0
   f(int{});                                 // print 0
 }
namespace detail {
    template<class> class type {};
    template<template<class...> class Temp, class...Ts>
    void try_deduce(type<Temp<Ts...>>);
}

template <template <class...> class, class, class = void>
struct IsSpecialization : std::false_type {};

template <template <typename...> class Temp, class Specialization>
struct IsSpecialization<Temp, Specialization, 
                        decltype(detail::try_deduce<Temp>(detail::type<Specialization>()))>
    : std::true_type {};

static_assert(IsSpecialization<SequenceExpr, SequenceExpr<int>>()());
static_assert(IsSpecialization<Expr, SequenceExpr<int>>()());
static_assert(!IsSpecialization<MergeExpr, SequenceExpr<int>>()());
static_assert(!IsSpecialization<SequenceExpr, MergeExpr<int>>()());