C++ static_assert 有什么作用,你会用它做什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1647895/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:45:52  来源:igfitidea点击:

What does static_assert do, and what would you use it for?

c++debuggingc++11assertstatic-assert

提问by AraK

Could you give an example where static_assert(...)('C++11') would solve the problem in hand elegantly?

你能举一个例子,其中static_assert(...)('C++11') 可以优雅地解决手头的问题吗?

I am familiar with run-time assert(...). When should I prefer static_assert(...)over regular assert(...)?

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

Also, in boostthere is something called BOOST_STATIC_ASSERT, is it the same as static_assert(...)?

另外,boost有一种叫做 的东西BOOST_STATIC_ASSERT,它和static_assert(...)?

采纳答案by Mark Rushakoff

Off the top of my head...

在我的头顶...

#include "SomeLibrary.h"

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

class UsingSomeLibrary {
   // ...
};

Assuming that SomeLibrary::Versionis declared as a static const, rather than being #defined (as one would expect in a C++ library).

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

Contrast with having to actually compile SomeLibraryand your code, link everything, and run the executable only thento find out that you spent 30 minutes compiling an incompatible version of SomeLibrary.

与必须实际编译SomeLibrary和您的代码、链接所有内容并运行可执行文件相比,然后才发现您花了 30 分钟编译了不兼容的SomeLibrary.

@Arak, in response to your comment: yes, you can have static_assertjust sitting out wherever, from the look of it:

@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;
}
$ g++ --std=c++0x a.cpp
a.cpp:7: error: static assertion failed: "Foo::bar is too small :("

回答by AnT

Static assert is used to make assertions at compile time. When the static assertion fails, the program simply doesn't compile. This is useful in different situations, like, for example, if you implement some functionality by code that critically depends on unsigned intobject having exactly 32 bits. You can put a static assert like this

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

static_assert(sizeof(unsigned int) * CHAR_BIT == 32);

in your code. On another platform, with differently sized unsigned inttype the compilation will fail, thus drawing attention of the developer to the problematic portion of the code and advising them to re-implement or re-inspect it.

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

For another example, you might want to pass some integral value as a void *pointer to a function (a hack, but useful at times) and you want to make sure that the integral value will fit into the pointer

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

int i;

static_assert(sizeof(void *) >= sizeof i);
foo((void *) i);

You might want to asset that chartype is signed

您可能想要对该char类型进行签名的资产

static_assert(CHAR_MIN < 0);

or that integral division with negative values rounds towards zero

或者负值的积分除法向零舍入

static_assert(-5 / 2 == -2);

And so on.

等等。

Run-time assertions in many cases can be used instead of static assertions, but run-time assertions only work at run-time and only when control passes over the assertion. For this reason a failing run-time assertion may lay dormant, undetected for extended periods of time.

在许多情况下,可以使用运行时断言代替静态断言,但运行时断言仅在运行时有效,并且仅在控制权越过断言时有效。出于这个原因,一个失败的运行时断言可能会处于休眠状态,长时间未被发现。

Of course, the expression in static assertion has to be a compile-time constant. It can't be a run-time value. For run-time values you have no other choice but use the ordinary assert.

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

回答by Matt Joiner

I use it to ensure my assumptions about compiler behaviour, headers, libs and even my own code are correct. For example here I verify that the struct has been correctly packed to the expected size.

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

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

In a class wrapping stdio.h's fseek(), I have taken some shortcuts with enum Originand check that those shortcuts align with the constants defined by stdio.h

在类包装stdio.h's 中fseek(),我采用了一些快捷方式,enum Origin并检查这些快捷方式是否与由stdio.h

uint64_t BasicFile::seek(int64_t offset, enum Origin origin)
{
    BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET);

You should prefer static_assertover assertwhen the behaviour is defined at compile time, and not at runtime, such as the examples I've given above. An example where this is notthe case would include parameter and return code checking.

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

BOOST_STATIC_ASSERTis a pre-C++0x macro that generates illegal code if the condition is not satisfied. The intentions are the same, albeit static_assertis standardised and may provide better compiler diagnostics.

BOOST_STATIC_ASSERT是一个 pre-C++0x 宏,如果不满足条件会生成非法代码。意图是相同的,尽管static_assert是标准化的并且可能提供更好的编译器诊断。

回答by nurettin

BOOST_STATIC_ASSERTis a cross platform wrapper for static_assertfunctionality.

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

Currently I am using static_assert in order to enforce "Concepts" on a class.

目前我正在使用 static_assert 来在类上强制执行“概念”。

example:

例子:

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 ... */
};

This will cause a compile time error if any of the above conditions are not met.

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

回答by Greg Hewgill

One use of static_assertmight be to ensure that a structure (that is an interface with the outside world, such as a network or file) is exactly the size that you expect. This would catch cases where somebody adds or modifies a member from the structure without realising the consequences. The static_assertwould pick it up and alert the user.

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

回答by vladon

In absence of concepts one can use static_assertfor simple and readable compile-time type checking, for example, in templates:

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

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

// ...
}

回答by nightlytrails

This doesn't directly answers the original question, but makes an interesting study into how to enforce these compile time checks prior to C++11.

这并没有直接回答原始问题,而是对如何在 C++11 之前强制执行这些编译时检查进行了有趣的研究。

Chapter 2 (Section 2.1) of Modern C++ Designby Andrei Alexanderscu implements this idea of Compile-time assertions like this

Andrei Alexanderscu的Modern C++ Design的第 2 章(第 2.1 节)实现了这种编译时断言的想法

template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};

#define STATIC_CHECK(expr, msg) \
{ CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

Compare the macro STATIC_CHECK() and static_assert()

比较宏 STATIC_CHECK() 和 static_assert()

STATIC_CHECK(0, COMPILATION_FAILED);
static_assert(0, "compilation failed");

回答by user11962338

The static_assertcan be used to forbid the use of the deletekeyword this way:

static_assert可用于禁止使用的delete这样的关键字:

#define delete static_assert(0, "The keyword \"delete\" is forbidden.");

#define delete static_assert(0, "The keyword \"delete\" is forbidden.");

Every modern C++ developer may want to do that if he or she wants to use a conservative garbage collector by using only classes and structs that overload the operator newto invoke a function that allocates memory on the conservative heap of the conservative garbage collector that can be initialized and instantiated by invoking some function that does this in the beginning of the mainfunction.

如果每个现代 C++ 开发人员想要使用保守垃圾收集器,那么他或她可能想要这样做,因为他或她只使用classes 和struct重载运算符 new来调用一个函数,该函数在保守垃圾收集器的保守堆上分配内存。可以通过调用一些在函数开始时执行此操作的函数来初始化和实例化main

For example every modern C++ developer that wants to use the Boehm-Demers-Weiser conservative garbage collector will in the beginning of the mainfunction write:

例如,每个想要使用 Boehm-Demers-Weiser 保守垃圾收集器的现代 C++ 开发人员都会在main函数的开头写下:

GC_init();

GC_init();

And in every classand structoverload the operator newthis way:

并且在每一个classstruct重载operator new这样:

void* operator new(size_t size)
{
     return GC_malloc(size);
}

And now that the operator deleteis not needed anymore, because the Boehm-Demers-Weiser conservative garbage collector is responsible to both free and deallocate every block of memory when it is not needed anymore, the developer wants to forbid the deletekeyword.

现在operator delete不再需要 ,因为 Boehm-Demers-Weiser 保守垃圾收集器负责在不再需要时释放和释放每个内存块,开发人员希望禁止该delete关键字。

One way is overloading the delete operatorthis way:

一种方法是这样重载delete operator

void operator delete(void* ptr)
{
    assert(0);
}

But this is not recommended, because the modern C++ developer will know that he/she mistakenly invoked the delete operatoron run time, but this is better to know this soon on compile time.

但不推荐这样做,因为现代 C++ 开发人员会知道他/她错误地调用了delete operator运行时,但最好在编译时尽快知道这一点。

So the best solution to this scenario in my opinion is to use the static_assertas shown in the beginning of this answer.

因此,在我看来,这种情况的最佳解决方案是使用static_assert本答案开头所示的 。

Of course that this can also be done with BOOST_STATIC_ASSERT, but I think that static_assertis better and should be preferred more always.

当然,这也可以用 来完成BOOST_STATIC_ASSERT,但我认为这样static_assert更好,应该更受欢迎。