【问题标题】:Filling N sized array with constexpr c++11使用Constexpr C ++ 11填充n大小的数组
【发布时间】:2019-01-16 04:30:36
【问题描述】:

我知道我的代码应该在 c++14 中工作,但我必须在 c++11 中复制这种行为,我无法制作等效的 init() 有人可以帮忙吗?

enum MyEnum {
    BANANA, APPLE, PINEAPPLE, ORANGE, FRUIT_AMOUNT
};

template<MyEnum>
struct Fruit{
    virtual ~Fruit(){}
    virtual void dostuff(){}
};

template <>
struct Fruit<ORANGE>{
    void dostuff(){ cout<<"Hey apple!"<<endl;
}

constexpr array< Fruit*, FRUIT_AMOUNT > init(){   
    array< Fruit*, FRUIT_AMOUNT > myArray;
    for(int i =0; i < FRUIT_AMOUNT; i++)
        myArray[i] = new Fruit< (MyEnum) i >();

    return myArray;     
}

array<Fruit*, FRUIT_AMOUNT> myPrettyFruits = init();

【问题讨论】:

    标签: c++11 templates c++14 template-meta-programming constexpr


    【解决方案1】:

    我知道我的代码应该在 c++14 中工作

    嗯……一点也不。

    你的代码有很多问题。

    其中一些,没有特定的顺序

    (1) 你不会写

    array<Fruit*, FRUIT_AMOUNT>
    

    因为Fruit 不是类型;这是一个模板类。

    所以,举例来说,Fruit&lt;BANANA&gt; 是一个类型,你可以这样写

    std::array<Fruit<BANANA> *, FRUIT_AMOUNT>
    

    但您不能有指向Fruit 的指针,因为Fruit(没有说明模板参数)不是类型。

    这个问题的一个可能的解决方案是让所有Fruit 类型继承自一个公共基础;举例

    struct FruitBase
     { };
    
    template <MyEnum>
    struct Fruit : public FruitBase
     {
       virtual ~Fruit () {}
       virtual void dostuff () {}
     };
    

    这样你就可以有一个FruitBase指针数组

    std::array<FruitBase *, FRUIT_AMOUNT>
    

    因此,您可以将数组指针放入Fruit&lt;Something&gt; 类型,这些类型也是FruitBase 指针。

    (2) 你不能拥有

    Fruit< (MyEnum) i >
    

    其中i 是运行时已知变量,因为模板参数必须是编译时已知的。

    一个可能的 C++14 解决方案是使用 std::make_index_sequence 获取模板序列(因此编译时已知)std::size_t 值。

    我建议如下

    template <std::size_t ... Is>
    constexpr std::array<FruitBase *, FRUIT_AMOUNT>
       init_helper (std::index_sequence<Is...> const &)
     { return { { (FruitBase*)(new Fruit<(MyEnum)Is>()) ... } }; }
    
    constexpr std::array<FruitBase *, FRUIT_AMOUNT> init ()
     { return init_helper(std::make_index_sequence<FRUIT_AMOUNT>{}); }
    

    注意这两个函数都是一个返回语句;这是constexpr C++11 函数所必需的。

    不幸的是,std::index_sequencestd::make_index_sequence 仅从 C++14 开始可用。但是可以用 C++11 替代它们。

    (3)new Something{}不能在编译时执行

    所以你可以定义init_helper()constexpr,但它是一个假的constexpr函数(所以init()也是一个假的constexpr函数)因为无法在编译时执行。

    所以你可以写

    std::array<FruitBase *, FRUIT_AMOUNT> myPrettyFruits = init();
    

    myPrettyFruits 是在运行时初始化的。

    如果你尝试在编译时初始化它

    constexpr std::array<FruitBase *, FRUIT_AMOUNT> myPrettyFruits = init();
    

    你得到一个编译错误。

    以下是一个完整的 C++11 编译示例,带有 std::index_sequence/std::make_index_sequence 替换,仅在运行时有效

    #include <array>
    #include <iostream>
    
    template <std::size_t...>
    struct indexSequence
     { using type = indexSequence; };
    
    template <typename, typename>
    struct concatSequences;
    
    template <std::size_t... S1, std::size_t... S2>
    struct concatSequences<indexSequence<S1...>, indexSequence<S2...>>
       : public indexSequence<S1..., ( sizeof...(S1) + S2 )...>
     { };
    
    template <std::size_t N>
    struct makeIndexSequenceH
       : public concatSequences<
                   typename makeIndexSequenceH<(N>>1)>::type,
                   typename makeIndexSequenceH<N-(N>>1)>::type>::type
     { };
    
    template<>
    struct makeIndexSequenceH<0> : public indexSequence<>
     { };
    
    template<>
    struct makeIndexSequenceH<1> : public indexSequence<0>
     { };
    
    template <std::size_t N>
    using makeIndexSequence = typename makeIndexSequenceH<N>::type;
    
    
    enum MyEnum
     { BANANA, APPLE, PINEAPPLE, ORANGE, FRUIT_AMOUNT };
    
    struct FruitBase
     { };
    
    template <MyEnum>
    struct Fruit : public FruitBase
     {
       virtual ~Fruit () {}
       virtual void dostuff () {}
     };
    
    template <>
    struct Fruit<ORANGE> : public FruitBase
     { void dostuff () { std::cout << "Hey apple!" << std::endl; } };
    
    // fake constexpr function: new can't be executed compile-time
    template <std::size_t ... Is>
    constexpr std::array<FruitBase *, FRUIT_AMOUNT>
          init_helper (indexSequence<Is...> const &)
     { return { { (FruitBase*)(new Fruit<(MyEnum)Is>()) ... } }; }
    
    // fake constexpr: init_helper() can't be executed compile-time
    constexpr std::array<FruitBase *, FRUIT_AMOUNT> init ()
     { return init_helper(makeIndexSequence<FRUIT_AMOUNT>{}); }
    
    int main ()
     {
       // compile (executed run-time)
       std::array<FruitBase *, FRUIT_AMOUNT> myPrettyFruits = init();
    
       // compilation error (init() can't be executed compile-time)
       //constexpr std::array<FruitBase *, FRUIT_AMOUNT> myPrettyFruits = init();
    
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多