问题 如何将模板模板与模板实例进行比较?
首先,我来介绍一个部分解决方案:
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
但是,它不适用于“元返回”模板模板,例如:
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
(这将是一个不太通用但足够的选项)似乎把我送到模板模式匹配的黑角。
6606
2018-03-04 12:08
起源
答案:
您可以检查是否可以更改 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()
{
}
4
2018-03-04 13:49
答案:
您可以检查是否可以更改 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()
{
}
4
2018-03-04 13:49
这是尝试用直接模板结构元编程和SFINAE解决问题。
该计划是2倍。首先,一个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<?...>
我们匹配的是一个不是直接别名的别名模板,它不会按照您的预期方式工作。如果它是一个直接的别名,你会变得很好。
不用多说,这是实现。
首先,Boilerplate类型包:
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...> > {};
实例
4
2018-03-04 21:20
你的原始实现不起作用的原因是,尽管如此 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
{
};
3
2018-03-04 14:04
如果专业 is_tbase_of
对于 quote
这是足够的,这应该工作:
template <template <class...> class Type,
typename ...Args>
struct is_tbase_of<quote<Type>::template type, Type<Args...>>:
std::true_type
{ };
2
2018-03-04 12:40