std::is_nothrow_destructible的奇怪行为

5
以下代码会触发static_assert,尽管我认为它不应该:
#include <type_traits>

template< typename T >
struct Tmp
{
  ~Tmp() noexcept( std::is_nothrow_destructible< T >::value ) {}
};

struct Foo;

struct Bar
{
  // Comment this out for the problem to go away
  Tmp< Foo > xx;

  // ..or this
  Bar() {}
};

struct Foo {};

// This triggers
static_assert( std::is_nothrow_destructible< Foo >::value, "That's odd" );

int main()
{
}

当使用以下编译选项编译时:

g++-4.9 -std=c++11 nothrow_destructible_bug.cc

下面将会发生以下事情:
nothrow_destructible_bug.cc:20:1: error: static assertion failed: That's odd
 static_assert( std::is_nothrow_destructible< Foo >::value, "That's odd" );
 ^

为什么在一个不相关的类中使用Foo来实例化模板会使其失去noexcept状态?我原以为这是编译器的bug,但我尝试了所有最近版本的gcc和clang都出现了相同的错误。


你是不是想检查 is_nothrow_destructible< Bar > 而不是 is_nothrow_destructible< Foo > - Captain Obvlious
1个回答

4
当你使用 Tmp< Foo > xx 时,Foo 是一个不完整的类型。这违反了使用 is_nothrow_destructible 的先决条件,并且其使用是未定义的行为。其中 UB 的一种可能性是 is_nothrow_destructible 为 false。
注释掉 Tmp 的使用将避免此问题。由于模板在使用时才实例化,因此注释掉构造函数也将避免该问题,因为模板尚未实例化。
struct Foo 的定义移动到 Bar 之前也应该避免这个问题。

"is_nothrow_destructable [sic] will be false." 这只是未定义行为。任何事情都有可能发生。 - T.C.
我想知道那些条件是什么,我在哪里可以阅读相关信息?这种情况下存在潜在的未定义行为让我感到担忧。 - dragonroot
@dragonroot 它们都在语言标准文档中。如果您的 is_nothrow_destructible 文档没有提到类型需要是完整类型,那么您应该提交一个缺陷报告。 - 1201ProgramAlarm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接