c++ - 在给定 constexpr 布尔选择函数的情况下对 Variadic 模板进行子集
问题描述
假设我们有一个可变参数模板类,如
template<class...Ts>
class X{
template<size_t I>
constexpr bool shouldSelect();
std::tuple<TransformedTs...> mResults; // this is want I want eventually
};
没有提供的实现shouldSelect
,但它的作用是,给定一个i
引用i
variadic 的第 th 元素的索引Ts
,告诉您我们是否应该将它选择到子集。
我想进行转换,以便只选择导致返回 true的索引处的Ts
classes 。是否有捷径可寻?T
shouldSelect
例如,如果当 I = 1,2,4 和 Ts... = short, int, double, T1, T2 时 shouldSelect 返回 true,那么我想获得TransformedTs...
由int, double, T2
. 然后我可以TransformedTs...
在同一个班级使用它。
解决方案
如果您能够使用 C++17,那么使用if constexpr
表达式折叠的组合很容易实现。
从一些辅助类型开始,一种带有用于跟踪参数的参数X::shouldSelect<I>()
,另一种带有要测试的类型。
template <typename T, size_t I, typename...Ts>
struct Accumulator {
using Type = std::tuple<Ts...>;
};
template <typename T>
struct Next { };
然后运算符重载将类型添加到累加器,或者不使用if constexpr
:
template <typename TAcc, size_t I, typename... Ts, typename TArg>
decltype(auto) operator +(Accumulator<TAcc, I, Ts...>, Next<TArg>) {
if constexpr (TAcc::template shouldSelect<I>()) {
return Accumulator<TAcc, I + 1, Ts..., TArg>{};
} else {
return Accumulator<TAcc, I + 1, Ts...>{};
}
}
最后,您可以将它们与折叠表达式放在一起,并使用 提取类型decltype
:
template <template <typename... Ts> class T, typename... Ts>
constexpr decltype(auto) FilterImpl(const T<Ts...>&) {
return (Accumulator<T<Ts...>, 0>{} + ... + Next<Ts>{});
}
template<typename T>
using FilterT = typename decltype(FilterImpl(std::declval<T>()))::Type;
用法:
using Result = FilterT<X<int, double, bool, etc>>;
演示:https ://godbolt.org/z/9h89zG
如果您没有可用的 C++17,它仍然是可能的。您可以使用递归继承链执行相同类型的条件类型传输,以遍历参数包中的每种类型,并std::enable_if
进行条件复制。下面是相同的代码,但在 C++11 中工作:
// Dummy type for copying parameter packs
template <typename... Ts>
struct Mule {};
/* Filter implementation */
template <typename T, typename Input, typename Output, size_t I, typename = void>
struct FilterImpl;
template <typename T, typename THead, typename... TTail, typename... OutputTs, size_t I>
struct FilterImpl<T, Mule<THead, TTail...>, Mule<OutputTs...>, I, typename std::enable_if<( T::template shouldSelect<I>() )>::type >
: FilterImpl<T, Mule<TTail...>, Mule<OutputTs..., THead>, (I + 1)>
{ };
template <typename T, typename THead, typename... TTail, typename... OutputTs, size_t I>
struct FilterImpl<T, Mule<THead, TTail...>, Mule<OutputTs...>, I, typename std::enable_if<( !T::template shouldSelect<I>() )>::type >
: FilterImpl<T, Mule<TTail...>, Mule<OutputTs...>, (I + 1)>
{ };
template <typename T, typename... OutputTs, size_t I>
struct FilterImpl<T, Mule<>, Mule<OutputTs...>, I>
{
using Type = std::tuple<OutputTs...>;
};
/* Helper types */
template <typename T>
struct Filter;
template <template <typename... Ts> class T, typename... Ts>
struct Filter<T<Ts...>> : FilterImpl<T<Ts...>, Mule<Ts...>, Mule<>, 0>
{ };
template <typename T>
using FilterT = typename Filter<T>::Type;
推荐阅读
- flutter - 匿名函数和回调...为什么不起作用?
- python - 更新:IndexError:索引 0 超出轴 0 的范围,大小为 0?
- optimization - 使用 scipy fsolve 求解非线性方程组(遇到数学域错误)
- ruby-on-rails - Shopify Liquid:将长字符串分成不同的列表
- powershell - 使用 PS 预先添加 AD 用户描述 - 使用 ForEach 进行重复更新
- python - 使用 SciPy 的线性代数方法求解三个联立方程
- python-3.x - Python - Kivy:标签在函数执行期间不更新
- c# - 无法从 Microsoft Access 在 DataGridView 上显示图像
- python - Google Cloud SDK 在 macOS Catalina 上发出警告:Executing a script that is loading libcrypto in an unsafe way
- c# - 无法在 Visual Studio 2019 中运行任何 .NET Core Web 应用程序