initializer_list :: size()上的static_assert

rcv*_*rcv 31 c++ initializer-list constexpr c++11

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

例如,以下代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

给出以下错误:

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
Run Code Online (Sandbox Code Playgroud)

请注意,这适用于一个简单的示例:

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

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

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

ale*_*cov 20

"初始化列表"只是可怕的克拉格.

别:

#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}); }
Run Code Online (Sandbox Code Playgroud)

做:

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}); }
Run Code Online (Sandbox Code Playgroud)

  • @Ela782:在这种情况下,“const T(&amp;)[N]”是一种类型(对“const T”类型的“N”元素数组的左值引用)。它被用作未命名的函数参数。如果要为参数指定名称,请使用“const T (&amp;name)[N]”。 (5认同)
  • @Ela782 `const &amp;T[N]` 声明一个引用数组(这在语义上是非法的),括号是声明对数组本身的引用所必需的。 (3认同)
  • `const T(&)[N]`这是什么语法?我需要搜索什么才能阅读更多相关信息? (2认同)
  • 这里使用 const T(&amp;list)[3] 不是更有意义吗?通过硬编码大小,我们根本不需要 static_assert。 (2认同)

Bo *_*son 11

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

我猜可以从具有不同长度初始化器的不同位置调用构造函数.

(详细说明:你试图写一个static_assert取决于变量的运行时值init,即它有多少元素.static_assert在编译函数时必须可以计算.你的代码类似于这个无效的例子:)

void foo(int i) { static_assert(i == 42, ""); }
int main() { foo(42); }  // but what if there's a caller in another translation unit?
Run Code Online (Sandbox Code Playgroud)

  • 是的,但这就是重点 - 每当有人使用大小不合适的初始化列表调用构造函数时,我想抛出一个 static_assertion 。因为 initializer_list 是由编译器构造的(并且没有公共构造函数),并且因为 size() 方法是一个 constexpr,所以我的 static_assert 应该是完全可能的。 (3认同)
  • 为什么不?想象一下,我有一个接受 T2 类型参数的模板构造函数。放置 static_assert 以确保(例如) std::is_integral&lt;T2&gt;::value 解析为“true”是完全可以接受的。这是有效的,因为 std::is_integral&lt;T2&gt;::value 是一个编译时常量,任何标记为 constexpr 的东西也是如此。std::initializer_list::size() 可以标记为 constexpr 的原因是因为它有一个只有编译器才能访问的特殊私有构造函数。 (3认同)

alf*_*lfC 5

从我与@Evgeny 的讨论中,我意识到这仅适用于(与gcc 4.8 c++11),并且也可以通过仅接受初始化列表(在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;
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

9640 次

最近记录:

7 年,1 月 前