如何将模板模板与模板实例进行比较
How to compare a template template with a template instance?
首先,让我向您介绍一个部分解决方案:
template <template <class...> class,
typename ...>
struct is_tbase_of:
std::false_type
{ };
template <template <class...> class Type,
typename ...Args>
struct is_tbase_of<Type, Type<Args...>>:
std::true_type
{ };
在常见情况下,它是有效的:
is_tbase_of<std::vector, std::is_integral<int>>::value; // false
is_tbase_of<std::vector, std::vector<int>>::value; // true
但是,它不适用于«meta return»模板模板,例如:
template <template <class ...> class T>
struct quote
{
template <typename ...U>
using type = T<U...>;
};
using QVec = quote<std::vector>;
is_tbase_of<QVec::template type, std::vector<int>>::value; // false...
我尝试了很多方法,试图获得第二种类型的模板参数(以比较引用的类型专门化),但似乎无法使它们发挥作用。即使将is_tbase_of
专门用于quote
(这将是一个不太通用但足够的选项),似乎也会让我陷入模板模式匹配的黑暗角落。
您可以检查是否可以将U<Args...>
更改为T<Args...>
,然后检查结果是否保持不变:
#include <type_traits>
#include <vector>
struct is_tbase_of_impl
{
struct err {};
template <template <class...> class T, class U>
static err test(U*);
template <template <class...> class T, template <class...> class U, class... Args>
static T<Args...> test(U<Args...>*);
};
template <template <class...> class T, class U>
using is_tbase_of
= typename std::is_same< decltype(is_tbase_of_impl::test<T>((U*)0)), U >::type;
template <template <class...> class T>
struct quote
{
template <class... U>
using type = T<U...>;
};
using QVec = quote<std::vector>;
template <class...> struct S {};
static_assert( !is_tbase_of< std::vector, std::is_integral<int> >::value, "" );
static_assert( is_tbase_of< std::vector, std::vector<int> >::value, "" );
static_assert( is_tbase_of< QVec::type, std::vector<int> >::value, "" );
static_assert( !is_tbase_of< std::vector, S<int, int, int> >::value, "" );
int main()
{
}
这是用直接模板结构元编程和SFINAE解决问题的一种尝试。
这个计划是两倍的。首先,一个traits类接受一个模板和一组参数,并回答"将一组参数应用于模板合法吗"。这是一个非常有用的结构:例如,给定一个SFINAE友好的result_of_t<F(Args...)>
,您可以在一行中编写can_invoke<F(Args...)>
。
其次,我们编写is_template_instance_of
。这里的目标是采用T<Args...>
类型和Z<?...>
模板,并查看Z<Args...>
是否与T<Args...>
类型相同。我们使用上面的can_apply
特征类来防止非法替换,然后做一个简单的is_same
测试。
该解决方案会产生一些误报和漏报,这取决于你如何看待它。基本上,如果我们匹配的模板Z<?...>
是一个不是直接别名的别名模板,它就不会像你预期的那样工作。如果它是一个直接的别名,你会很好。
事不宜迟,下面是实现。
第一,锅炉板类型包装:
template<class...>struct types {using type=types;};
在C++1z中有void_t
,我在这里重新实现了它:
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
给定Z<?...>
和types<Ts...>
,检查Z<Ts...>
是否有效:
template<template<class...>class Z, class types, class=void>
struct can_apply : std::false_type {};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, types<Ts...>, void_t<Z<Ts...>>> : std::true_type {};
现在,SFINAE保护测试:
template<template<class...>class Z, class T, class=void>
struct is_template_instance_of : std::false_type {};
template<template<class...>class Z, template<class...>class Y, class... Ts>
struct is_template_instance_of<
Z, Y<Ts...>,
std::enable_if_t<can_apply< Z, types<Ts...> >{}>
> : std::is_same< Z<Ts...>, Y<Ts...> > {};
实例
原始实现不起作用的原因是,即使QVec::type<Args...>
与std:vector<Args...>
是同一类型,但QVec::type
与std::vector
不是同一个模板,因此它与部分专用化不匹配。
这可以从一个更简单的例子中看出:
template <template <typename...> class> struct test {
static const bool value = false;
};
template <>
struct test<std::vector> {
static const bool value = true;
};
test<std::vector>::value; // true
test<QVec::type>::value; // false
以下是一种几乎有效的方法:
template <template <class...> class Type1,
template <class...> class Type2,
typename... Args>
struct is_tbase_of<Type1, Type2<Args...>>:
std::is_same<Type1<Args...>,Type2<Args...>>
{
};
然而,正如@Alex所指出的,这并不能处理第二个模板的参数与第一个模板不兼容的情况。这可以使用enable_if
:解决
template <template <class...> class, typename, typename=void>
struct is_tbase_of : std::false_type { };
template <template <class...> class Type1,
template <class...> class Type2,
typename... Args>
struct is_tbase_of<Type1, Type2<Args...>,
typename std::enable_if<
std::is_same<Type1<Args...>,Type2<Args...>>::value
>::type>
: std::true_type
{
};
如果将is_tbase_of
专门化为quote
就足够了,那么这应该有效:
template <template <class...> class Type,
typename ...Args>
struct is_tbase_of<quote<Type>::template type, Type<Args...>>:
std::true_type
{ };
- 从C++实例化QML
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- C++的解析器在可以区分比较和模板实例化之前会做什么?
- 比较两个 std::chrono::time_point 实例时出错
- 如何键入定义一个专门的 std::set 模板,使用特定的比较函数实例化
- 如何将理论效率与实践实例进行比较
- 没有成员作为唯一标识符的两个类实例的比较
- 无法理解浮点数和对象实例化之间比较的原因
- 如何将模板模板与模板实例进行比较
- 为什么没有询问priority_queue实例化中比较器的模板参数
- C++将向量迭代器与实例进行比较
- 用于C++的分析器如何区分比较和模板实例化
- 如何在定义映射/集合时实例化比较函数(函子)
- 如何在 C++ 中将类的实例与 char * 变量进行比较
- 指向同一个模板化函数的不同实例的指针保证比较不相等
- C++std列表排序使用自定义比较器,该比较器依赖于对象实例的成员变量
- c++ STL容器.为每个不同的实例参数化比较器
- is_same将类模板实例化与其基类模板进行比较时返回 false
- 使用不同类型的比较实例构造priority_queue实例