static_assert做了什么,你会用它做什么?

Ara*_*raK 110 c++ debugging assert static-assert c++11

你能举个例子static_assert(...)来优雅地解决问题吗?

我熟悉运行时assert(...).我什么时候应该static_assert(...)比常规更喜欢assert(...)

此外,boost有一个叫做的东西BOOST_STATIC_ASSERT,它是一样的static_assert(...)吗?

AnT*_*AnT 125

静态断言用于在编译时进行断言.当静态断言失败时,程序根本无法编译.这在不同情况下很有用,例如,如果您通过严格依赖于unsigned int具有正好32位的对象的代码实现某些功能.你可以像这样放一个静态断言

static_assert(sizeof(unsigned int) * CHAR_BIT == 32);
Run Code Online (Sandbox Code Playgroud)

在你的代码中.在另一个平台上,使用不同大小的unsigned int类型,编译将失败,从而引起开发人员对代码中有问题部分的注意,并建议他们重新实现或重新检查它.

再举一个例子,您可能希望将一些整数值作为void *指向函数的指针传递(一个hack,但有时很有用),并且您希望确保整数值适合指针

int i;

static_assert(sizeof(void *) >= sizeof i);
foo((void *) i);
Run Code Online (Sandbox Code Playgroud)

您可能希望资产char类型已签名

static_assert(CHAR_MIN < 0);
Run Code Online (Sandbox Code Playgroud)

或者负值的积分除以零

static_assert(-5 / 2 == -2);
Run Code Online (Sandbox Code Playgroud)

等等.

在许多情况下可以使用运行时断言而不是静态断言,但运行时断言仅在运行时才起作用,并且仅在控制通过断言时才起作用.由于这个原因,失败的运行时断言可能处于休眠状态,长时间未检测到.

当然,静态断言中的表达式必须是编译时常量.它不能是运行时值.对于运行时值,您没有其他选择,只能使用普通值assert.

  • @Trevor Hickey:是的,是的。但我并没有试图特别引用 C++11 中的 `static_assert`。我上面的 `static_assert` 只是静态断言的一些抽象实现。(我个人在 C 代码中使用类似的东西)。我的回答是关于静态断言的一般用途及其与运行时断言的区别。 (3认同)
  • 是否不是static_assert需要字符串文字作为第二个参数? (2认同)

Mar*_*off 76

脱离我的头顶......

#include "SomeLibrary.h"

static_assert(SomeLibrary::Version > 2, 
         "Old versions of SomeLibrary are missing the foo functionality.  Cannot proceed!");

class UsingSomeLibrary {
   // ...
};
Run Code Online (Sandbox Code Playgroud)

假设它SomeLibrary::Version被声明为静态const,而不是#defined(正如人们在C++库中所期望的那样).

相比之下,必须实际编译SomeLibrary和您的代码,链接一切,然后运行可执行文件,然后找出你花了30分钟编译不兼容的版本SomeLibrary.

@Arak,回应你的评论:是的,你可以static_assert从任何地方坐下来,从外观上看:

class Foo
{
    public: 
        static const int bar = 3;
};

static_assert(Foo::bar > 4, "Foo::bar is too small :(");

int main()
{ 
    return Foo::bar;
}
Run Code Online (Sandbox Code Playgroud)
$ g++ --std=c++0x a.cpp
a.cpp:7: error: static assertion failed: "Foo::bar is too small :("

  • @monocoder:请参阅以"与......对比"开头的段落.简而言之:**assert**在运行时检查其条件,**static_assert**在编译时检查其条件.因此,如果您声明的条件在编译时已知,请使用`static_assert`.如果在程序运行之前不知道条件,请使用`assert`. (10认同)
  • 是的,静态断言,因为它们的立场通常被实现为创建一个仅在谓词为真时才定义的对象.这只会成为全球性的. (3认同)
  • 我有点困惑,你能把 `static_assert` 放在非执行上下文中吗?这似乎是一个很好的例子:) (2认同)
  • 这个答案没有提供任何有关**assert**与<cassert>和**static_assert**之间区别的细节** (2认同)

Mat*_*ner 12

我用它来确保我对编译器行为,头文件,库甚至我自己的代码的假设是正确的.例如,我在此验证结构已正确打包到预期大小.

struct LogicalBlockAddress
{
#pragma pack(push, 1)
    Uint32 logicalBlockNumber;
    Uint16 partitionReferenceNumber;
#pragma pack(pop)
};
BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6);
Run Code Online (Sandbox Code Playgroud)

在一类包装stdio.hfseek(),我已经采取了一些快捷方式enum Origin,并检查这些快捷键与定义的常量对齐stdio.h

uint64_t BasicFile::seek(int64_t offset, enum Origin origin)
{
    BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET);
Run Code Online (Sandbox Code Playgroud)

你应该更喜欢static_assertassert当行为是在编译时定义,而不是在运行时,如我上面给出的例子.不是这种情况的示例包括参数和返回码检查.

BOOST_STATIC_ASSERT是一个前C++ 0x宏,如果不满足条件,它会生成非法代码.意图是相同的,虽然static_assert是标准化的,可能提供更好的编译器诊断.


nur*_*tin 9

BOOST_STATIC_ASSERT是一个跨平台的static_assert功能包装器.

目前我正在使用static_assert来强制类的"概念".

例:

template <typename T, typename U>
struct Type
{
  BOOST_STATIC_ASSERT(boost::is_base_of<T, Interface>::value);
  BOOST_STATIC_ASSERT(std::numeric_limits<U>::is_integer);
  /* ... more code ... */
};
Run Code Online (Sandbox Code Playgroud)

如果不满足上述任何条件,这将导致编译时错误.

  • 现在C++ 11已经出来了(并且已经有一段时间了),所有主要编译器的更新版本都应该支持static_assert.对于我们这些不能等待C++ 14(希望包含模板约束)的人来说,这是一个非常有用的static_assert应用程序. (3认同)

Gre*_*ill 7

的一种用法static_assert是确保结构(即与外界的接口,例如网络或文件)恰好与您期望的大小相同。这将捕获某些情况,即有人从结构中添加或修改成员而没有意识到后果。该static_assert会捡起来,并提醒用户。


vla*_*don 5

在缺乏概念的情况下,我们可以使用static_assert简单且可读的编译时类型检查,例如在模板中:

template <class T>
void MyFunc(T value)
{
static_assert(std::is_base_of<MyBase, T>::value, 
              "T must be derived from MyBase");

// ...
}
Run Code Online (Sandbox Code Playgroud)