static_assert 在编译时知道索引
static_assert on indices know at compile time
有没有办法对编译时已知的索引进行静态断言,而 运行-time 断言否则?示例:
template <class T, int Dim>
class Foo
{
T _data[Dim];
public:
const T &operator[](int idx) const
{
static_assert(idx < Dim, "out of range"); // error C2131: expression did not evaluate to a constant
return _data[idx];
}
};
int main()
{
Foo<float, 2> foo;
foo[0];
foo[1];
foo[2]; // compiler error
for (int i=0; i<5; ++i)
{
foo[i]; // run time assert when i > 1
}
return 0;
}
我觉得用一个函数是不可能得到你想要的东西的。
即使您开发了一个 constexpr
函数,我认为您无法检测到何时执行 run-time 以及何时执行编译时间并以不同的方式执行。
但是你可以开发不同的功能。
例如,模板 get<>()
,其中模板参数是索引,只能与 compile-time 处已知的索引一起使用,并且可以执行 static_assert()
,和一个 at(std::size_t)
,它可以接收在 运行 时间计算的索引,并使用 运行 时间检查。
路人:
1) 我建议像在 STL 中一样,使用 at()
进行绑定检查访问,使用 operator[]()
进行绑定未检查访问
2) 我建议使用无符号索引,否则您必须检查索引是否为 >= 0
.
下面是一个工作示例
#include <iostream>
#include <stdexcept>
template <class T, std::size_t Dim>
class Foo
{
private:
T _data[Dim];
public:
T const & operator[] (std::size_t idx) const
{ return _data[idx]; }
template <std::size_t IDX>
T const & get () const
{
static_assert(IDX < Dim, "out of range");
return this->operator[](IDX);
}
T const & at (std::size_t idx) const
{
if ( idx >= Dim )
throw std::range_error("out of range");
return this->operator[](idx);
}
};
int main ()
{
Foo<float, 2U> foo;
foo.get<0U>();
foo.get<1U>();
//foo.get<2U>(); // compiler error
for ( auto i = 0U ; i < 5U ; ++i )
foo.at(i); // run time exception when i > 1
return 0;
}
您可以简单地抛出异常或断言。它将在 constexpr 上下文中编译失败。这仅在可以在 constexpr 上下文中评估抛出条件时才有效。
请注意,某些版本的 gcc 中存在一个错误,该错误会阻止 throw 工作。
有没有办法对编译时已知的索引进行静态断言,而 运行-time 断言否则?示例:
template <class T, int Dim>
class Foo
{
T _data[Dim];
public:
const T &operator[](int idx) const
{
static_assert(idx < Dim, "out of range"); // error C2131: expression did not evaluate to a constant
return _data[idx];
}
};
int main()
{
Foo<float, 2> foo;
foo[0];
foo[1];
foo[2]; // compiler error
for (int i=0; i<5; ++i)
{
foo[i]; // run time assert when i > 1
}
return 0;
}
我觉得用一个函数是不可能得到你想要的东西的。
即使您开发了一个 constexpr
函数,我认为您无法检测到何时执行 run-time 以及何时执行编译时间并以不同的方式执行。
但是你可以开发不同的功能。
例如,模板 get<>()
,其中模板参数是索引,只能与 compile-time 处已知的索引一起使用,并且可以执行 static_assert()
,和一个 at(std::size_t)
,它可以接收在 运行 时间计算的索引,并使用 运行 时间检查。
路人:
1) 我建议像在 STL 中一样,使用 at()
进行绑定检查访问,使用 operator[]()
进行绑定未检查访问
2) 我建议使用无符号索引,否则您必须检查索引是否为 >= 0
.
下面是一个工作示例
#include <iostream>
#include <stdexcept>
template <class T, std::size_t Dim>
class Foo
{
private:
T _data[Dim];
public:
T const & operator[] (std::size_t idx) const
{ return _data[idx]; }
template <std::size_t IDX>
T const & get () const
{
static_assert(IDX < Dim, "out of range");
return this->operator[](IDX);
}
T const & at (std::size_t idx) const
{
if ( idx >= Dim )
throw std::range_error("out of range");
return this->operator[](idx);
}
};
int main ()
{
Foo<float, 2U> foo;
foo.get<0U>();
foo.get<1U>();
//foo.get<2U>(); // compiler error
for ( auto i = 0U ; i < 5U ; ++i )
foo.at(i); // run time exception when i > 1
return 0;
}
您可以简单地抛出异常或断言。它将在 constexpr 上下文中编译失败。这仅在可以在 constexpr 上下文中评估抛出条件时才有效。 请注意,某些版本的 gcc 中存在一个错误,该错误会阻止 throw 工作。