cons 变量的静态断言?

发布于 2024-09-03 08:08:43 字数 1135 浏览 5 评论 0原文

静态断言对于在编译时检查事物非常方便。一个简单的静态断言习惯用法如下所示:

template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)

这对于 and 之类的东西很有用

STATIC_ASSERT(sizeof(float) == 4)

#define THIS_LIMIT (1000)
...
STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT);

但是使用 #define 并不是定义常量的“C++”方式。 C++ 会让你使用匿名命名空间:

namespace {
    const int THIS_LIMIT = 1000;
}

甚至:

static const int THIS_LIMIT = 1000;

这样做的问题是,使用 const int 时,你不能使用 STATIC_ASSERT() ,而必须求助于运行时检查这是愚蠢的。

在当前的 C++ 中是否有办法正确解决这个问题?
我想我已经读过 C++0x 有一些工具可以做到这一点...


编辑

好的,所以这

static const int THIS_LIMIT = 1000;
...
STATIC_ASSERT(THIS_LIMIT > 0);

编译得很好
但这:

static const float THIS_LIMIT = 1000.0f;
...
STATIC_ASSERT(THIS_LIMIT > 0.0f);

不是。
(在 Visual Studio 2008 中)

怎么会这样?

Static asserts are very convenient for checking things in compile time. A simple static assert idiom looks like this:

template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)

This is good for stuff like

STATIC_ASSERT(sizeof(float) == 4)

and:

#define THIS_LIMIT (1000)
...
STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT);

But using #define is not the "C++" way of defining constants. C++ would have you use an anonymous namespace:

namespace {
    const int THIS_LIMIT = 1000;
}

or even:

static const int THIS_LIMIT = 1000;

The trouble with this is that with a const int you can't use STATIC_ASSERT() and you must resort to a run-time check which is silly.

Is there a way to properly solve this in current C++?
I think I've read C++0x has some facility to do this...


EDIT

Ok so this

static const int THIS_LIMIT = 1000;
...
STATIC_ASSERT(THIS_LIMIT > 0);

compiles fine
But this:

static const float THIS_LIMIT = 1000.0f;
...
STATIC_ASSERT(THIS_LIMIT > 0.0f);

does not.
(in Visual Studio 2008)

How come?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

随遇而安 2024-09-10 08:08:43

为什么,你仍然可以使用 const int 进行静态断言:

#define static_assert(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])]
static_assert( THIS_LIMIT > OTHER_LIMIT )

另外,使用 boost

BOOST_STATIC_ASSERT( THIS_LIMIT > OTHER_LIMIT )

...您会收到很多更好的错误消息...

Why, you can still static assert with const int:

#define static_assert(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])]
static_assert( THIS_LIMIT > OTHER_LIMIT )

Also, use boost!

BOOST_STATIC_ASSERT( THIS_LIMIT > OTHER_LIMIT )

... you'll get a lot nicer error messages...

傾旎 2024-09-10 08:08:43

static_assert 是 C++0x 中的编译器功能,因此只要您拥有相对最新的编译器,就可以使用它。请注意执行 #define static_assert(x) ...,因为它是 C++0x 中的真正关键字,因此您将永久隐藏编译器功能。另外,C++0x static_assert 采用两个参数(例如 static_assert(sizeof(int) == 4, "Expecting int to be 4 bytes")),因此您如果您使用#define,可能会导致您将来尝试切换时出现问题。

static_assert is a compiler feature in C++0x so as long as you've got a relatively up-to-date compiler you can use that. Watch out for doing #define static_assert(x) ..., because it's a real keyword in C++0x so you'd be permanently hiding the compiler feature. Also, C++0x static_assert takes two parameters (eg. static_assert(sizeof(int) == 4, "Expecting int to be 4 bytes")), so you could cause yourself problems trying to switch in future if you use that #define.

我们只是彼此的过ke 2024-09-10 08:08:43

看来您真的问为什么会出现以下情况(我可以在 GCC 4.3.4 和 Visual C++ 2008 Express 中确认这一点):

template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)


static const int   AN_INT  = 1000;
static const float A_FLOAT = 1000.0f;

int main()
{
   STATIC_ASSERT(AN_INT > 0);     // OK
   STATIC_ASSERT(A_FLOAT > 0.0f); // Error: A_FLOAT may not appear in a constant expression
}

使用浮点有很多限制静态值。例如,请注意,您不能将它们作为模板参数传递。那是因为:

[C++11: 5.19/2]: 条件表达式是核心常量表达式,除非它涉及以下内容之一作为潜在的求值子表达式 (3.2),但不考虑未求值的逻辑 AND (5.14)、逻辑 OR (5.15) 和条件 (5.16) 运算的子表达式 [ 注意: 重载运算符调用一个
功能。 —尾注]

  • [..]
  • 左值到右值的转换 (4.1),除非它应用于
    • 整型或枚举类型的泛左值,引用具有前面初始化的非易失性 const 对象,并使用常量表达式进行初始化,或者
    • 文字类型的泛左值,引用用 constexpr 定义的非易失性对象,或者引用此类对象的子对象,或者
    • 文字类型的泛左值,指的是生命周期尚未结束的非易失性临时对象,用常量表达式初始化;
  • [..]

(即只允许整型和枚举类型;不允许浮点类型。)

至于此规则的原因,我不完全确定,但以下理由可能是我们与它有关:

[C++11: 5.19/4]: [..] 由于本国际标准对
浮点运算的准确性,未指定翻译过程中浮点表达式的计算是否会产生与相同表达式的计算相同的结果(或对相同值进行相同的操作)<程序执行期间。 [..]

It seems that you're really asking why the following is the case (and I can confirm that in both GCC 4.3.4 and Visual C++ 2008 Express):

template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)


static const int   AN_INT  = 1000;
static const float A_FLOAT = 1000.0f;

int main()
{
   STATIC_ASSERT(AN_INT > 0);     // OK
   STATIC_ASSERT(A_FLOAT > 0.0f); // Error: A_FLOAT may not appear in a constant expression
}

There are number of restrictions on using floating-point values statically. Note, for example, that you cannot pass them as template arguments. That is because:

[C++11: 5.19/2]: A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered [ Note: An overloaded operator invokes a
function. —end note ]:

  • [..]
  • an lvalue-to-rvalue conversion (4.1) unless it is applied to
    • a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or
    • a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object, or
    • a glvalue of literal type that refers to a non-volatile temporary object whose lifetime has not ended, initialized with a constant expression;
  • [..]

(i.e. only integral and enumeration types are allowed; no floating-point types.)

As for the reason for this rule, I'm not entirely sure, but the following sort of rationale may well have something to do with it:

[C++11: 5.19/4]: [..] Since this International Standard imposes no restrictions on the
accuracy of floating-point operations, it is unspecified whether the evaluation of a floating-point expression during translation yields the same result as the evaluation of the same expression (or the same operations on the same values) during program execution. [..]

说不完的你爱 2024-09-10 08:08:43

也许您将 C++ 的行为与 C 混淆了,其中 const int 并不代表真正的编译时常量。或者你的 C++ 编译器可能坏了。如果确实是后者,请改用enum

Perhaps you're confusing C++'s behavior with C, where const int does not represent a true compile-time constant. Or perhaps your C++ compiler is broken. If it's truly the latter, use enum instead.

归属感 2024-09-10 08:08:43

这:

namespace {
    const int THIS_LIMIT = 1000;
}

template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)

int main()
{
    STATIC_ASSERT(THIS_LIMIT > 5);

    return (0);
}

用 VC 和 Comeau 编译得很好。

This:

namespace {
    const int THIS_LIMIT = 1000;
}

template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)

int main()
{
    STATIC_ASSERT(THIS_LIMIT > 5);

    return (0);
}

compiles fine with VC and Comeau.

天气好吗我好吗 2024-09-10 08:08:43

枚举{THIS_LIMIT = 1000};

enum{THIS_LIMIT = 1000};

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文