36

为什么在 a 中是std::initializer_list<_E>::size不允许的static_assert,即使它constexpr在我的 libstdc++ (v. 4.6)中被声明为 a ?

例如,下面的代码:

template<class T, int Length>
class Point
{
  public:
    Point(std::initializer_list<T> init)
    {
      static_assert(init.size() == Length, "Wrong number of dimensions");
    }
};

int main()
{
  Point<int, 3> q({1,2,3});

  return 0;
}

给出以下错误:

test.C: In constructor ‘Point<T, Length>::Point(std::initializer_list<_Tp>) [with T = int, int Length = 3]’:
test.C:60:26:   instantiated from here
test.C:54:7: error: non-constant condition for static assertion
test.C:54:73:   in constexpr expansion of ‘init.std::initializer_list<_E>::size [with _E = int, std::initializer_list<_E>::size_type = long unsigned int]()’
test.C:54:7: error: ‘init’ is not a constant expression

请注意,这对于一个简单的示例来说效果很好:

class A
{
  public:
    constexpr int size() { return 5; }
};

int main()
{
  A a;
  static_assert(a.size() == 4, "oh no!");

  return 0;
}
4

5 回答 5

34

“初始化列表”只是可怕的组合。

不:

#include <initializer_list>

template<typename T>
void Dont(std::initializer_list<T> list) { // Bad!
    static_assert(list.size() == 3, "Exactly three elements are required.");
}

void Test() { Dont({1,2,3}); }

做:

template<typename T, std::size_t N>
void Do(const T(&list)[N]) { // Good!
    static_assert(N == 3, "Exactly three elements are required.");
}

void Test() { Do({1,2,3}); }
于 2016-07-31T01:12:39.157 回答
11

编译器说问题是 init,而不是 init.size()。

我猜可以使用不同长度的初始化器从不同的地方调用构造函数。

(详细说明:您正在尝试编写一个static_assert取决于变量的运行时值init,即它有多少元素。static_asserts 在编译函数时必须是可评估的。您的代码与此类似无效的例子:)

void foo(int i) { static_assert(i == 42, ""); }
int main() { foo(42); }  // but what if there's a caller in another translation unit?
于 2011-03-25T22:31:38.377 回答
5

从我与@Evgeny 的讨论中,我意识到这只是工作(使用gcc 4.8 c++11),并且也可以通过只接受初始化列表(in main)中的兼容大小来进行大小检查。

(代码链接:http ://coliru.stacked-crooked.com/a/746e0ae99c518cd6 )

#include<array>
template<class T, int Length>
class Point
{
  public:
    Point(std::array<T, Length> init)
    {
//not needed//      static_assert(init.size() == Length, "Wrong number of dimensions");
    }
};

int main()
{
  Point<int, 3> q({1,2,3}); //ok
//  Point<int, 3> q2({1,2,3,4}); //compile error (good!)
  Point<int, 3> q2({1,2}); // ok, compiles, same as {1,2,0}, feature or bug?
  return 0;
}
于 2013-11-12T11:12:45.103 回答
2

使用以下语法:

现场演示

#include <initializer_list>

template<class T, int Length>
class Point
{
    std::initializer_list<T> data;
public:
    constexpr Point(std::initializer_list<T> init)
        : data
        (
            init.size() == Length ?
            init : throw 0
        )
    {}
};

int main()
{
    constexpr Point<int, 3> a{{1,2,3}};
    constexpr Point<int, 2> b{{1,2,3}}; // compile time error
}

请参阅以下 SO


编辑:有趣的是适用于 GCC 4.8.1,但不适用于 Clang 3.4。也许这与constexpr.size()afaik,在 C++14 中是constexpr)有关。

于 2013-04-08T21:29:25.917 回答
0

我还没有真正弄清楚这里发生了什么。

如果我说

const std::initializer_list<double> li = { 1, 2.5, 3.7, 4.3 };
static_assert(li.size() == 4, "fail");

我抱怨说“li”没有被宣布为“constexper”。

但如果我说

constexpr std::size_t dSize(std::initializer_list<double> di)
{
    return di.size();
}

然后

static_assert(dSize({1, 2.5, 3.7, 4.3}) == 4, "failed");   // works

static_assert(dSize(li) == 4, "failed");

失败并显示“错误:'li' 的值在常量表达式中不可用”

这就是 -std=c++11

So, somehow, an initializer list passed into an arg list can be part of a constant expression, but an initializer list just declared as a const variable can't.

于 2020-10-15T21:07:10.807 回答