简体   繁体   English

使用参数包扩展生成Constexpr

[英]Using Parameter Pack Expansion to Generate a Constexpr

I have the following code: 我有以下代码:

#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; }
};

I am trying to create a bitmask based on the EvenType arguments passed into the template. 我正在尝试根据传递到模板中的EvenType参数创建位掩码。 Unfortunately the number of EvenTypes passed is variadic. 不幸的是,传递的EvenTypes的数量是可变的。 But since we have all the arguments at compile time it seems like it should be more than possible to calculate a value based on the given arguments at compile time as a constexpr . 但是由于我们在编译时拥有所有参数,因此似乎应该比在编译时基于给定参数作为constexpr来计算一个值更有可能。 What I get on the other hand is: 另一方面,我得到的是:

expression did not evaluate to a constant

For the listeners variable. 对于listeners变量。 Any ideas? 有任何想法吗? Thanks in advance. 提前致谢。

PS On a completely unrelated note if anyone has any idea how I can eliminate the lengthy friend class declaration without taking a performance hit and keeping the InternalGetType() function hidden I would love and greatly appreciate hearing it. PS在一个完全不相关的注释上,如果有人有任何想法,我可以消除冗长的朋友类声明而又不影响性能,并且不隐藏InternalGetType()函数,我将非常喜欢,并且非常感谢听到它。

Edit 编辑

In response to a recent suggestion I am limited to using C++14 为了回应最近的建议,我仅限于使用C ++ 14

Edit 编辑

This is what I have done to make it work using recursive template calls crtp.h 这是我使用递归模板调用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 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;
}

If you can use C++17, fold expressions (see HolyBlackCat's answer) is (IMHO) a way really simple and elegant to solve the problem. 如果可以使用C ++ 17,则折叠表达式(请参阅HolyBlackCat的答案)是(IMHO)解决问题的一种真正简单而优雅的方法。

If you can't use C++17... the best I can imagine is the development of a static constexpr method for class A ; 如果您不能使用C ++ 17 ...,我能想象的最好的就是为class A开发static constexpr方法了; something as follows 如下

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

   unsigned short  ret { 0 };

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

   return ret;
 }

So you can initialize listener in this way 因此您可以通过这种方式初始化listener

static constexpr unsigned short listeners = calcCombinedBitMask();

For C++11, I suggest a solution a little different from you own 对于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...>(); }

That asks for fold expressions . 这要求折叠表达 Note that they're a relatively new feature, added in C++17. 请注意,它们是C ++ 17中新增的相对较新的功能。

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

Also you forgot to make CalcBitMask() constexpr . 您也忘记了让CalcBitMask() constexpr

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

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