2015-10-06 9 views
5

次のコード、私はそれが必要とは思わないにもかかわらずstatic_assertをトリガー:STDの奇妙な行動:: is_nothrow_destructible

#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のステータスが失われますか?私はこれがコンパイラのバグだと思っていましたが、gccとclangの最近のすべてのバージョンで試してみましたが、すべて同じエラーが出るようです。

+0

'is_nothrow_destructible < Foo >'の代わりに 'is_nothrow_destructible < Bar >'をチェックしたのですか? –

答えて

4

Tmp<Foo> xxを使用する場合、Fooは不完全なタイプです。これは、is_nothrow_destructibleの使用の前提条件の1つに違反し、その使用は未定義の動作です。そのUBの1つの可能性は、is_nothrow_destructibleが偽であることです。

Tmpの使用をコメントアウトすると、その問題を回避できます。テンプレートは使用されるまでインスタンス化されていないので、テンプレートがまだインスタンス化されていないので、コンストラクターをコメントアウトすることでも問題を回避できます。

struct Fooの定義を移動する前に、Barもこの問題を回避する必要があります。

+0

"is_nothrow_destructable [sic]はfalseになります。それは単にUBです。何でも起れる。 –

+0

私はそれらの条件が何であり、どこで私がそれらについて読むことができるのだろうか?この場合、静かなUBがあるという事実は私を怖がらせます – dragonroot

+0

@dragonroot彼らはすべて言語標準文書に入っています。 is_nothrow_destructibleのドキュメントに、タイプが完全なタイプである必要があることが記載されていない場合は、そのタイプの欠陥レポートを提出する必要があります。 – 1201ProgramAlarm