【问题标题】:static_assert does not break compiling immediatelystatic_assert 不会立即中断编译
【发布时间】:2013-12-07 12:21:09
【问题描述】:

代码示例:

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版

【问题讨论】:

  • 你知道-Wfatal-errors吗?
  • @zch 我最近有它向我指出-Wfatal-errors 中止 用于自动脚本以外的用途。实际错误消息后面的相关信息也将被省略。
  • @Ali Ha,这正是我向我指出的地方。它可以被认为是重复的,但我认为不是,因为即使问题相似,答案也会有所不同:我的答案是我在 cmets 中提到的一个坏主意,但我认为它是一个很好的方法。 :)

标签: c++ templates c++11 static-assert


【解决方案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 &lt; 0的任何东西,如果模板没有被实例化,也不能递归实例化。

我最初使 SUM 派生自 SUM_impl,但不这样做(并复制其值)可提供更好的诊断。

【讨论】:

  • @Mat 对我来说,clang 给出了我最初在答案中给出的内容,但不是我编辑的版本。 GCC 仍然给出了一个额外的“错误:‘struct std::enable_if’中没有名为‘type’的类型”。但这不是重点,重点是static_assert 消息会很快出现,并且没有大量其他消息。我没有尝试获取 no 其他消息。 :)
猜你喜欢
  • 1970-01-01
  • 2018-03-12
  • 2019-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-07
  • 1970-01-01
  • 2021-09-03
相关资源
最近更新 更多