constexpr循环中std :: array的值初始化是否有效?

时间:2017-03-06 19:49:46

标签: c++ c++14 constexpr

以下代码:

#include<iostream>
#include<array>

using std::size_t;
using std::array;

//#define INIT_BY_HAND 1
#define CONSTEXPR 1

#ifdef CONSTEXPR
constexpr
#endif
size_t accumulator_count()
{
    constexpr size_t nb_rows{2};
    constexpr size_t nb_cols{2};
    size_t nb{0};
    for(size_t k = 0; k < nb_rows; ++k)
    {
        array<size_t,nb_cols> acc{}; // value initialization: expect both elements to be zero
        //for const_cast/static_cast see http://stackoverflow.com/questions/34199774/why-is-non-const-stdarrayoperator-not-constexpr
    #ifdef INIT_BY_HAND
        for(size_t j = 0; j < nb_cols; ++j)
            const_cast<size_t&>(static_cast<array<size_t,nb_cols> const&>(acc)[j]) = 0;
    #endif
        if(k == 0)
            const_cast<size_t&>(static_cast<array<size_t,nb_cols> const&>(acc)[0]) = 1;
        if(k == 1)
            const_cast<size_t&>(static_cast<array<size_t,nb_cols> const&>(acc)[nb_cols-1]) = 1;
        for(size_t j = 0; j < nb_cols; ++j)
            nb += size_t(static_cast<array<size_t,nb_cols> const&>(acc)[j] != 0);
    }
    return nb;
}

int main()
{
#ifdef CONSTEXPR
    constexpr
#endif
    size_t nb{accumulator_count()};
    std::cout << "nb: " << nb << std::endl;
}

在gcc 5.3.1(-Wall -std = c ++ 14)上编译时没有警告,但它会产生错误的输出3.

没有constexpr(注释掉#define CONSTEXPR 1行)它正确输出2.

手动初始化(#define INIT_BY_HAND 1行注释),它正确输出2.

使用clang 3.8.0编译,正确输出2。

问题:此代码是否符合c ++ 14标准或我错过了什么?

1 个答案:

答案 0 :(得分:3)

g ++ 6.3.0和clang ++ 3.8.0都编译并生成值2。

live example

这有力地表明g ++ 5.3.1出错了。

暂且不说:

namespace notstd {
  template<class T, std::size_t N>
  constexpr T& constexpr_get( std::array<T, N>& arr, std::size_t I ) {
    return const_cast<T&>(const_cast<std::array<T,N> const&>(arr)[I]);
  }
  struct at {
    std::size_t I = 0;
    constexpr at(std::size_t i):I(i){}
    template<class T, std::size_t N>
    friend constexpr T&
    operator->*( std::array<T, N>& arr, at a ) {
      return constexpr_get(arr, a.I);
    }
    // optional
    template<class T, std::size_t N>
    friend constexpr T const&
    operator->*( std::array<T, N> const& arr, at a ) {
      return arr[a.I];
    }
  };
}

using notstd::at为您提供了比所有演员更漂亮的中缀方式:

arr->*at(0) = 1;

(谁说我们在C ++中还没有扩展方法?)