Luk*_*rth 9 c++ templates metaprogramming c++17
我需要一些代码来检查某个模板是否属于参数包。为了实现对普通班级的检查,我使用了路易斯·迪昂(Louis Dionne)或奥古斯汀·贝格(AgustínBergé)概述的基于多重继承的方法。
这个想法是,您将包中的每个类T包装到一个PackEntry类中,然后PackIndex从所有PackEntry类中继承。这样,如果您正在寻找一个类A,您要做的就是检查a是否PackIndex可以转换为正确的PackEntry。将所有内容放在一起,看起来像这样:
#include <cstddef>
#include <utility>
template <class T>
struct PackEntry
{
using type = T;
};
template <class... Ts>
struct PackIndex : PackEntry<Ts>...
{};
template <class T, class... Ts>
struct PackSearcher
{
static constexpr std::false_type check(...);
// This overload is used if the PackIndex below
// derives from PackEntry<T>, the overload above
// otherwise.
static constexpr std::true_type check(PackEntry<T>);
using type =
decltype(check(PackIndex<Ts...>{}));
static constexpr bool
value()
{
return type{};
}
};
template <class... Ts>
struct Pack
{
template<class T>
static constexpr bool has() {
return PackSearcher<T, Ts...>::value();
}
};
int main() {
static_assert(Pack<int, void>::has<int>());
static_assert(! Pack<int, void>::has<bool>());
}
Run Code Online (Sandbox Code Playgroud)
现在,这一切都很好,但是说我有一个模板Tmpl,并且我想知道我的背包中是否包含该模板的任何特殊化。如果模板具有特定形式,我很容易做,template <std::size_t> class Tmpl {};基本上说,唯一的区别是PackSearcher(现在称为)内部TmplPackSearcher,是让编译器为N模板导出正确的模板参数。
#include <cstddef>
#include <utility>
template <class T>
struct PackEntry
{
using type = T;
};
template <class... Ts>
struct PackIndex : PackEntry<Ts>...
{
};
template <template <std::size_t> class T, class... Ts>
struct TmplPackSearcher
{
static constexpr std::false_type check(...);
template <std::size_t N>
static constexpr std::true_type check(PackEntry<T<N>>);
using type =
decltype(check(PackIndex<Ts...>{}));
static constexpr bool
value()
{
return type{};
}
};
template <class... Ts>
struct Pack
{
template<template <std::size_t> class T>
static constexpr bool has_tmpl() {
return TmplPackSearcher<T, Ts...>::value();
}
};
template<std::size_t I>
class Tmpl {};
int main() {
static_assert(Pack<Tmpl<1>, int>::has_tmpl<Tmpl>());
static_assert(!Pack<int>::has_tmpl<Tmpl>());
}
Run Code Online (Sandbox Code Playgroud)
现在,我的问题是:如何在不做任何假设的情况下测试参数包中是否存在模板?即,我不想单独写的代码template<std::size_t>,template<std::size_t, typename>,template <typename, typename>,等。
如果可以使用相同的多重继承技巧完成,则将获得加分。
正如@MaxLanghof 在评论中提到的,甚至不可能声明has_tmpl接受任意类型的模板。可以has_tmpl使用不同的模板参数(template<std::size_t> class、template<std::size_t, typename> class、template <typename, typename> class等)进行重载,但需要无限数量的重载。
相反,让我们使用包装模板的类型,并公开我们需要的一切。据我所知,最简单的方法是 (ab) 使用 lambda: []<std::size_t I>(type_identity<Tmpl<I>>){}。
然后问题几乎是微不足道的:has_tmpl可以简单地定义为 return (std::is_invocable_v<Lambda,type_identity<Ts>> || ...)。
完整示例:
#include <type_traits>
template<class> struct type_identity {};
template <class... Ts>
struct Pack
{
template<class Lambda>
static constexpr bool has_tmpl(Lambda) {
return (std::is_invocable_v<Lambda, type_identity<Ts>> || ...);
}
};
template<std::size_t I>
class Tmpl {};
int main() {
static_assert(Pack<Tmpl<1>, int>::has_tmpl([]<std::size_t I>(type_identity<Tmpl<I>>){}));
static_assert(!Pack<int>::has_tmpl([]<std::size_t I>(type_identity<Tmpl<I>>){}));
}
Run Code Online (Sandbox Code Playgroud)
请注意,这使用了 C++20 中标准化的 GNU 扩展(通用 lambda 的模板参数列表)。我认为这是无法避免的。
应该可以使用多重继承,但折叠表达式要短得多;)
| 归档时间: |
|
| 查看次数: |
246 次 |
| 最近记录: |