static_assert不会立即中断编译

static_assert does not break compiling immediately

本文关键字:中断 编译 assert static      更新时间:2023-10-16

代码示例:

template <int x>
struct SUM
{
    static_assert(x >= 0, "X must be greater or equal to 0");
    enum {VALUE = x + SUM<x-1>::VALUE};
};
template<>
struct SUM<0>
{
    enum {VALUE = 0};
};
int main()
{
    std::cout << SUM<-1>::VALUE << std::endl;
    return 0;
}

为什么编译器不中断第一个static_assert的编译,而是继续工作直到达到最大实例化深度?

Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -MMD -MP -MF"src/Main.d" -MT"src/Main.d" -o "src/Main.o" "../src/Main.cpp"
../src/Main.cpp: In instantiation of ‘struct SUM<-1>’:
../src/Main.cpp:47:22:   required from here
../src/Main.cpp:26:2: error: static assertion failed: X must be greater or equal to 0
  static_assert(x >= 0, "X must be greater or equal to 0");
  ^
......
../src/Main.cpp: In instantiation of ‘struct SUM<-2>’:
../src/Main.cpp: In instantiation of ‘struct SUM<-900>’:
../src/Main.cpp:27:18:   recursively required from ‘struct SUM<-2>’
../src/Main.cpp:27:18:   required from ‘struct SUM<-1>’
../src/Main.cpp:47:22:   required from here
../src/Main.cpp:26:2: error: static assertion failed: X must be greater or equal to 0
../src/Main.cpp:27:18: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) instantiating ‘struct SUM<-901>’
  enum {VALUE = x + SUM<x-1>::VALUE};
                  ^
../src/Main.cpp:27:18:   recursively required from ‘struct SUM<-2>’
../src/Main.cpp:27:18:   required from ‘struct SUM<-1>’
../src/Main.cpp:47:22:   required from here
../src/Main.cpp:27:18: error: incomplete type ‘SUM<-901>’ used in nested name specifier
make: *** [src/Main.o] Error 1
13:04:05 Build Finished (took 6s.877ms)

这里唯一的问题是,它需要很长时间才能休息,并产生大量的输出。有没有办法让这件事变得更好?使用的编译器:gcc版本4.8.1

语言中没有任何东西需要立即中止编译,因此直接回答您问题的任何东西都必须是特定于实现的,并且不会避免其他实现上的实例化。我认为最好是以这样一种方式重新编写代码,即它没有任何方法继续实例化。一种可能的方法是使用std::enable_if:

#include <iostream>
#include <type_traits>
template <int x, typename = typename std::enable_if<x >= 0>::type>
struct SUM_impl
{
    enum {VALUE = x + SUM_impl<x-1>::VALUE};
};
template<>
struct SUM_impl<0>
{
    enum {VALUE = 0};
};
template <int x>
struct SUM
{
    static_assert(x >= 0, "X must be greater or equal to 0");
    enum {VALUE = SUM_impl<x>::VALUE};
};
int main()
{
    std::cout << SUM<-1>::VALUE << std::endl;
    return 0;
}

通过这种方式,SUM中的static_assert打印出一条用户友好的消息。SUM_impl中的enable_if在模板被实例化之前,强制拒绝x < 0中的任何内容,如果模板没有被实例化,也不能递归实例化。

我最初让SUMSUM_impl派生,但不这样做(并复制其值)可以提供更好的诊断。