我试图确定如何接受布尔模板参数包
template<bool...B> struct BoolPack{};
并从中构造一个整数参数包,其中的值表示true
中BoolPack
元素的枚举。枚举可以包含如下:
template<size_t...I> struct IntegerSequence{};
该功能应该包含BoolPack<B...>
并返回IntegerSequence<I...>
;
template<bool...B>
constexpr auto enumerate( const BoolPack<B...>& b ) {
// Combination of cumulative sum and mask?
return IntegerSequence<???>();
}
例如,如果输入为
BoolPack<true,false,true,false,true> b;
该功能应该返回
IntegerSequence<1,0,2,0,3> e();
我对如何实现这一点的最佳猜测是计算部分和 第k个模板参数是
的位置K = K-1 + static_cast<size_t>(get<K>(make_tuple<B...>));
我不确定这是不是这样做的。难道没有一种更直接的方法不需要制作元组吗?应用递归应该导致
IntegerSequence<1,1,2,2,3> s();
然后将此分量乘以原始BoolPack
的元素。这是要走的路,还是我可以在没有元组的情况下做到这一点?
谢谢!
答案 0 :(得分:4)
您的实施方式
template<bool...B>
constexpr auto enumerate( const BoolPack<B...>& b ) {
// Combination of cumulative sum and mask?
return IntegerSequence<???>();
}
无法工作,因为C ++是一种强类型语言,因此返回的类型不能取决于从编译时可以执行的代码中获得的总和。
我知道这些值在编译时是已知的,因此值可以在编译时计算;但是我看到的最佳方式是通过特定的类型特征。
通过示例(抱歉:将IntegerSequence
重命名为IndexSequence
,使其更接近C ++ 14 std::index_sequence
)
template <std::size_t, typename, std::size_t ...>
struct BoolIndexer
{ };
template <std::size_t N, bool ... Bs, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<true, Bs...>, Is...>
: public BoolIndexer<N+1U, BoolPack<Bs...>, Is..., N>
{ };
template <std::size_t N, bool ... Bs, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<false, Bs...>, Is...>
: public BoolIndexer<N, BoolPack<Bs...>, Is..., 0U>
{ };
template <std::size_t N, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<>, Is...>
{ using type = IndexSequence<Is...>; };
以下是完整的编译示例
#include <iostream>
#include <type_traits>
template <bool ... B>
struct BoolPack
{ };
template<size_t...I>
struct IndexSequence
{ };
template <std::size_t, typename, std::size_t ...>
struct BoolIndexer
{ };
template <std::size_t N, bool ... Bs, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<true, Bs...>, Is...>
: public BoolIndexer<N+1U, BoolPack<Bs...>, Is..., N>
{ };
template <std::size_t N, bool ... Bs, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<false, Bs...>, Is...>
: public BoolIndexer<N, BoolPack<Bs...>, Is..., 0U>
{ };
template <std::size_t N, std::size_t ... Is>
struct BoolIndexer<N, BoolPack<>, Is...>
{ using type = IndexSequence<Is...>; };
int main ()
{
using type1 = BoolPack<true,false,true,false,true>;
using type2 = typename BoolIndexer<1U, type1>::type;
static_assert( std::is_same<type2, IndexSequence<1,0,2,0,3>>{}, "!" );
}
如果你真的需要一个函数来获得转换,使用BoolIndexer
类型特征你可以简单地写如下
template <bool ... Bs>
constexpr auto getIndexSequence (BoolPack<Bs...> const &)
-> typename BoolIndexer<1U, BoolPack<Bs...>>::type
{ return {}; }
并以这种方式调用
auto is = getIndexSequence(BoolPack<true,false,true,false,true>{});
答案 1 :(得分:1)
另一种可能的解决方案是通过创建constexpr
函数
template <bool ... Bs>
constexpr std::size_t getNumTrue (BoolPack<Bs...> const &, std::size_t top)
{
using unused = int[];
std::size_t cnt = -1;
std::size_t ret { 0 };
(void)unused { 0, (++cnt <= top ? ret += Bs : ret, 0)... };
return ret;
}
可以调用来设置IndexSequence
的模板值;不幸的是,下面的示例使用std::make_index_sequence
和std::index_sequence
作为C ++ 14(从...开始)功能
template <bool ... Bs, std::size_t ... Is>
constexpr auto gisH (BoolPack<Bs...> const &,
std::index_sequence<Is...> const &)
-> IndexSequence<(Bs ? getNumTrue(BoolPack<Bs...>{}, Is) : 0U)...>
{ return {}; }
template <bool ... Bs>
constexpr auto getIndexSequence (BoolPack<Bs...> const & bp)
{ return gisH(bp, std::make_index_sequence<sizeof...(Bs)>{}); }
以下是完整的编译示例
#include <utility>
#include <iostream>
#include <type_traits>
template <bool ... B>
struct BoolPack
{ };
template <std::size_t...I>
struct IndexSequence
{ };
template <bool ... Bs>
constexpr std::size_t getNumTrue (BoolPack<Bs...> const &, std::size_t top)
{
using unused = int[];
std::size_t cnt = -1;
std::size_t ret { 0 };
(void)unused { 0, (++cnt <= top ? ret += Bs : ret, 0)... };
return ret;
}
template <bool ... Bs, std::size_t ... Is>
constexpr auto gisH (BoolPack<Bs...> const &,
std::index_sequence<Is...> const &)
-> IndexSequence<(Bs ? getNumTrue(BoolPack<Bs...>{}, Is) : 0U)...>
{ return {}; }
template <bool ... Bs>
constexpr auto getIndexSequence (BoolPack<Bs...> const & bp)
{ return gisH(bp, std::make_index_sequence<sizeof...(Bs)>{}); }
int main()
{
using typeBP = BoolPack<true,false,true,false,true>;
auto is = getIndexSequence(typeBP{});
static_assert( std::is_same<decltype(is),
IndexSequence<1,0,2,0,3>>{}, "!" );
}