我有以下代码:
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...>;
此函数有时会收到SequenceExpr<Something>
作为模板参数:
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)
//...
}
我希望能够检测FullExpr
是否是SequenceExpr
的特化,但由于某种未知原因而失败。
答案 0 :(得分:4)
为什么失败很容易。对于SequenceExpr<ExtraArgs...>
,Temp2
推断为Expr
,Ts...
推断为ExprKindSequence, ExtraArgs...
。然后Temp1<Ts...>
为Expr<ExprKindSequence, ExprKindSequence, ExtraArgs...>
,显然与Temp2<Ts...>
不同。
我知道没有完全通用的方法来做到这一点。毕竟,这样一个假设的模板可能需要返回true
IsSpecialization<std::remove_reference_t, int>
...
如果我们将其限制为在可推导的上下文中使用其参数的别名模板(在您的示例中就是这种情况),那么一种可能的方法是提出问题&#34;我可以推断Ts...
in来自Temp<Ts...>
的{{1}}?&#34;:
Specialization
答案 1 :(得分:1)
如果您对SequenceExpr
的专业化感兴趣 ,我能想象的最好的是添加IsSpecialization
的专业化定义如下
template <typename... Ts>
struct IsSpecialization<SequenceExpr, Expr<ExprKindSequence, Ts...>>
: std::true_type
{ };
显然,这不是我认为不可能的一般解决方案。
如果您使用(例如)f
值来呼叫Expr<ExprKindSequence, int, long>
f(Expr<ExprKindSequence, int, long>{}); // result true !!!
匹配上方IsSpecialization
的专业化,您得到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
}