是否可以基于模板参数有条件地添加C++元组元素类型



我试图根据一些编译时条件有条件地将类型添加到元组模板类型中,如下所示:

template <typename T>
class Base { ... }
template <int I>
class Derived : public Base<std::tuple<std::conditional<I % 8 == 0, int,    void>::type,
std::conditional<I % 4 == 0, double, void>::type,
std::conditional<I % 2 == 0, float,  void>::type>>
{ ... }

我知道这不是有效的代码,但从概念上讲,我试图有条件地将类型添加到元组的列表中。我希望在条件解析为void时跳过该类型。

有办法做这样的事情吗?

问题的一小部分无法计算:

std::conditional<I % 1 == 0, float,  void>:

由于任何整数除以1的余数都是0,因此此条件将始终为真。

无论这里的实际意图是什么,我只会举一个例子,其中有两个条件句,可以根据需要简单地扩展为包括额外的条件句:

#include <tuple>
#include <functional>
template <typename T>
class Base {};
template <int I>
class Derived : public Base<
decltype(std::tuple_cat(
std::declval<
std::conditional_t<I % 4 == 0,
std::tuple<int>,
std::tuple<>>>(),
std::declval<
std::conditional_t<I % 2 == 0,
std::tuple<float>,
std::tuple<>>>()
))>
{
};
Derived<4> a;
Base<std::tuple<int, float>> &b=a;
Derived<2> c;
Base<std::tuple<float>> &d=c;

这是利用了std::tuple_catstd::tuple<>非常满意的事实,我们只需要(ab(使用它将元组的正确组合粘合在一起。

让我给出一个替代解决方案(有关详细信息,请参阅Sam的回答(:

template<bool... Fs, class... Ts>
auto filter_tuple(std::tuple<Ts...>) {
return std::tuple_cat(
std::conditional_t<Fs, std::tuple<Ts>, std::tuple<>>()...);
}
template<typename T>
class Base { };
template<int I>
using Base_t = decltype(filter_tuple<!(I % 4), !(I % 2),  !(I % 1)>(
std::tuple<int,      double,    float>{}));
static_assert(std::is_same_v<Base_t<1>, std::tuple<float>>);
static_assert(std::is_same_v<Base_t<2>, std::tuple<double, float>>);
static_assert(std::is_same_v<Base_t<4>, std::tuple<int, double, float>>);

演示

template <class..Ts>
struct types {
template <template <class...> class Z>
using apply = Z<Ts...>;
template<class...Us>
constexpr types <Ts...,Us...> operator+(types<Us...>)const{return {};}
};

现在

template <unsigned int I>
class Derived : public Base<decltype(
std::conditional_t<I & 4 == 0, types<int>, types<>> +
std::conditional_t<I & 2 == 0, types<double>, types<>>{} +
std::conditional_t<I & 1 == 0, types<float>,  types<>>{})::template apply<std::tuple>
>

就这样。

当然,在c++20中,您可以直接传递types对象。

最新更新