将变换后的integer_sequence插入到可变参数模板参数中?

时间:2014-06-08 20:16:15

标签: c++ templates c++11 variadic-templates

如何将变换的integer_sequence(或类似的,因为我将C ++ 11作为目标)插入到可变参数模板参数中?

例如,我有一个表示一组逐位标志的​​类(如下所示)。它是使用嵌套类生成的,因为同一个类不能有两个可变参数模板参数。它将像typedef Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::WithValues<0x01, 0x02, 0x04> MyFlags一样使用。通常,它们将与2的幂一起使用(尽管并非总是如此,在某些情况下会进行某些组合,例如,可以想象一组标志,如Read = 0x1,Write = 0x2和ReadWrite = 0x3为0x1 = | 0X2)。我想提供一种方法typedef Flags<unsigned char, FLAG_A, FLAG_B, FLAG_C>::WithDefaultValues MyFlags

template<class _B, template <class,class,_B> class... _Fs>
class Flags
{
public:
    template<_B... _Vs>
    class WithValues :
      public _Fs<_B, Flags<_B,_Fs...>::WithValues<_Vs...>, _Vs>...
    {
        // ...
    };
};

我尝试了以下但没有成功(放在Flags类中,在WithValues类之外):

private:
    struct _F {
        // dummy class which can be given to a flag-name template
        template <_B _V> inline constexpr
        explicit _F(std::integral_constant<_B, _V>) { } };

        // we count the flags, but only in a dummy way
        static constexpr unsigned _count = sizeof...(_Fs<_B, _F, 1>); 

        static inline constexpr
        _B pow2(unsigned exp, _B base = 2, _B result = 1) {
            return exp < 1 ?
                    result :
                    pow2(exp/2,
                         base*base,
                         (exp % 2) ? result*base : result);
        }

    template <_B... _Is>  struct indices          {
        using next = indices<_Is..., sizeof...(_Is)>;
        using WithPow2Values = WithValues<pow2(_Is)...>;
    };
    template <unsigned N> struct build_indices    {
        using type = typename build_indices<N-1>::type::next;
    };
    template <>           struct build_indices<0> {
        using type = indices<>;
    };

    //// Another attempt
    //template <            _B... _Is> struct indices {
    //    using WithPow2Values = WithValues<pow2(_Is)...>;
    //};
    //template <unsigned N, _B... _Is> struct build_indices            
    //                   : build_indices<N-1, N-1, _Is...> { };
    //template <            _B... _Is> struct build_indices<0, _Is...> 
    //                                         : indices<_Is...>       { };

public:
    using WithDefaultValues =
            typename build_indices<_count>::type::WithPow2Values;

当然,我愿意为整个情况提供任何其他选择(在同一模板集中支持标志名称和值等)。

我在ideone中包含了一个“工作”示例:http://ideone.com/NYtUrg - 通过“工作”我的意思是在不使用默认值的情况下编译正常但是使用默认值失败(在它们之间切换#define)。 / p>

谢谢!

1 个答案:

答案 0 :(得分:0)

所以我自己想出来了,我想我发布的太快了。

我能够通过上面的build_indicesindices模板类中的虚拟模板参数来解决使用给定代码生成的错误。参数必须是一个类型名,因为它们目前有可变积分类型。

(注意:此处仍然使用不正确的_F名称 - 我已更正我的个人代码以不使用这些保留名称 - 感谢提示)

这是一个有效的解决方案,它使WithValues<...>模板根据Flags可变参数模板的大小填充2(1,2,4,8,16 ......)的幂。

private:
// dummy class which can be given to a flag-name template
struct _F
{
    template <_B _V> inline constexpr
    explicit _F(std::integral_constant<_B, _V>) { }
};

// we count the flags, but only in a dummy way
static constexpr unsigned _count = sizeof...(_Fs<_B, _F, 1>); 

static inline constexpr
_B pow2(unsigned exp, _B base = 2, _B result = 1)
{
    return exp < 1 ?
            result :
            pow2(exp/2, base*base, (exp % 2) ? result*base : result);
}

template <class dummy, _B... _Is>  struct indices
{
    using next = indices<dummy, _Is..., sizeof...(_Is)>;
    using WithPow2Values = WithValues<pow2(_Is)...>;
};
template <class dummy, unsigned N> struct build_indices
{
    using type = typename build_indices<dummy, N-1>::type::next;
};
template <class dummy> struct build_indices<dummy, 0>
{
    using type = indices<dummy>;
};

public:
using WithDefaultValues =
        typename build_indices<void, _count>::type::WithPow2Values;