我试图根据一些编译时条件有条件地将类型添加到元组模板类型中,如下所示:
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_cat
对std::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
对象。