繁体   English   中英

使用参数包扩展生成Constexpr

[英]Using Parameter Pack Expansion to Generate a Constexpr

我有以下代码:

#include <vector>
#include <array>

using std::vector;

enum EventType {
    EventType_Collision,
    EventType_Accelerate,
    EventType_Glide
};

template<class T, EventType... events>
class A {
private:
    static unsigned short CalcBitMask(EventType e) { return 1 << e; }
    static constexpr unsigned short listeners = 0 | CalcBitMask(events)...;
protected:
    //static constexpr int InternalGetType() { return 0; }
public:
    static constexpr int GetType() { return T::InternalGetType(); }
    static constexpr int GetListeners() { return listeners; }
};

class B : public A<B, EventType_Accelerate, EventType_Collision > {
    friend class A<B, EventType_Accelerate, EventType_Collision>;
protected:
    static constexpr int InternalGetType() { return 1; }
};

我正在尝试根据传递到模板中的EvenType参数创建位掩码。 不幸的是,传递的EvenTypes的数量是可变的。 但是由于我们在编译时拥有所有参数,因此似乎应该比在编译时基于给定参数作为constexpr来计算一个值更有可能。 另一方面,我得到的是:

expression did not evaluate to a constant

对于listeners变量。 有任何想法吗? 提前致谢。

PS在一个完全不相关的注释上,如果有人有任何想法,我可以消除冗长的朋友类声明而又不影响性能,并且不隐藏InternalGetType()函数,我将非常喜欢,并且非常感谢听到它。

编辑

为了回应最近的建议,我仅限于使用C ++ 14

编辑

这是我使用递归模板调用crtp.h使其工作的结果

#pragma once
#include <vector>
#include <array>

using std::vector;

enum EventType {
    EventType_Collision,
    EventType_Accelerate,
    EventType_Glide
};

template<class T, EventType... events>
class A {
private:
    template <EventType Last>
    static constexpr unsigned short BitCalc() {
        return 1 << Last;
    }

    template <EventType First, EventType Second, EventType ...Rest>
    static constexpr unsigned short BitCalc() {
        return BitCalc<First>() | BitCalc<Second, Rest...>();
    }
    static constexpr unsigned short listeners = BitCalc<events...>();
protected:
    //static constexpr int InternalGetType() { return 0; }
public:
    static constexpr int GetType() { return T::InternalGetType(); }
    static constexpr int GetListeners() { return listeners; }
};

class B : public A<B, EventType_Accelerate, EventType_Collision > {
    friend class A<B, EventType_Accelerate, EventType_Collision>;
protected:
    static constexpr int InternalGetType() { return 1; }
};

main.cpp

#include "ctrp.h"
#include <iostream>
#include <vector>
#include<bitset>

using std::cout;
using std::vector;
using std::getchar;
using std::endl;

int main() {
    B b;
    cout << "Bitmask: " << std::bitset<16>(b.GetListeners());
    getchar();
    return 0;
}

如果可以使用C ++ 17,则折叠表达式(请参阅HolyBlackCat的答案)是(IMHO)解决问题的一种真正简单而优雅的方法。

如果您不能使用C ++ 17 ...,我能想象的最好的就是为class A开发static constexpr方法了; 如下

constexpr static unsigned short calcCombinedBitMask ()
 {
   using unused = unsigned short [];

   unsigned short  ret { 0 };

   (void)unused { 0, ret |= CalcBitMask(events)... };

   return ret;
 }

因此您可以通过这种方式初始化listener

static constexpr unsigned short listeners = calcCombinedBitMask();

对于C ++ 11,我建议一种与您自己的解决方案略有不同的解决方案

static constexpr unsigned short CalcBitMask (EventType e)
 { return 1 << e; }

static constexpr unsigned short BitCalc()
 { return 0; }

template <EventType First, EventType ... Rest>
static constexpr unsigned short BitCalc()
 { return CalcBitMask(First) | BitCalc<Rest...>(); }

这要求折叠表达 请注意,它们是C ++ 17中新增的相对较新的功能。

static constexpr unsigned short listeners = (CalcBitMask(events) | ...);

您也忘记了让CalcBitMask() constexpr

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM