6

次のスニペットを検討してください。

#include <utility>

template <typename U>
auto foo() -> decltype(std::declval<U>() + std::declval<U>());

template <typename T>
decltype(foo<T>()) bar(T)
{}

int main()
{
    bar(1);
    return 0;
}

これにより、GCC のすべてのバージョン (4.7.3、4.8.1、4.9-some-git) でコンパイルしたときに、警告-Wall -Wextra静的アサーション エラーが発生します。たとえば、これは 4.8.1 の出力です。

main.cpp: 'decltype (foo<T>()) bar(T) [with T = int; のインスタンス化中。decltype (foo<T>()) = int]':
main.cpp:12:7: ここから必須
main.cpp:8:2: 警告: 非 void [-Wreturn-type] を返す関数に return ステートメントがありません
 {}
  ^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/move.h:57:0 からインクルードされたファイルで、
                 /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/stl_pair.h:59 から、
                 /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/utility:70 から、
                 main.cpp:1 から:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/type_traits: 'typename std::add_rvalue_reference< <template-parameter-1-1> >::type のインスタンス化std::declval() [with _Tp = int; typename std::add_rvalue_reference< <template-parameter-1-1> >::type = int&&]':
main.cpp:8:2: 'decltype (foo<T>()) bar(T) [with T = int; から必要です。decltype (foo<T>()) = int]'
main.cpp:12:7: ここから必須
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/type_traits:1871:7: エラー: 静的アサーションに失敗しました: declval() は使用しないでください!
       static_assert(__declval_protector::__stop,

警告を無効にするか returnbarステートメントを指定すると、たとえば、

template <typename T>
decltype(foo<T>()) bar(T a)
{
    return a + a;
}

アサーションの失敗はなくなります。Clang++ 3.3 では、どのような場合でもアサーション エラーは発生しません。これは GCC の標準準拠の動作ですか?

4

2 に答える 2

6

return {};6 月初旬にビルドされた GCC 4.9 のコピーは、関数を追加またはthrow;内部に追加する限り、問題なくコンパイルされます。noreturnを指定すると、その静的アサーションが起動されます。これは確かにバグですが、関数は実行時にのみ「クラッシュ」するため、軽微なものです。

定数式で実行しようとしたときにそのエラーを見たdeclval()ので、そのようなことがあなたの場合に起こっている可能性があります。「使用できない」とは、おそらく ODR の使用または結果の使用を指しています。

おそらく、何の声明もなかったので、decltype. のような単純なステートメントを追加すると0;、偽のエラーが沈黙します。(しかし、static_assert( true, "" )またはvoid(0)不十分です。)

GCC バグを報告しました。

于 2013-07-09T02:24:55.343 に答える
2

コンパイラがこのプログラムのコンパイルに失敗する権利があるとは思いません。このプログラムの致命的なエラーは、IME、非準拠です。(警告、OTOH はまったく問題ありません。コンパイラは、実際に有効なプログラムをコンパイルする場合、必要に応じて、return ステートメントの欠落、奇妙な継承イディオム、識別子のイギリス/アメリカのスペル、または文字列リテラルの人種差別的なコメントについて警告することができます。)

値を返さない関数を無条件に実行するため、プログラムを実行すると未定義の動作が発生すると思います。ただし、コンパイラがこのプログラムを実際にコンパイルすることを許すとは思いません。プログラムをコンパイルし、実行可能ファイルをテープ バックアップにコピーすれば、二度とそれを見ることはありません。bar()さらに、コンパイラがこのプログラムに対してエラーを出力した場合、それをチェックした後にのみ呼び出されたプログラムに対してエラーを出力する可能性が高くargc==1、コンパイラの UB 権限の範囲内にないことを期待しています。

厳密に言えば、コンパイラはすべての状況で準拠していると見なされる必要はありません。準拠するコンパイラは、有効な C++ プログラムをコンパイルできればよいだけです。このプログラムは なし-Wallでコンパイルできるため、そのフラグが渡されなくても GCC は準拠していると主張できます。ただし、警告を有効にすると不適合エラーが発生するのは驚くべきことです。そのため、これを GCC の適合性の問題として特徴付けようと思います。

于 2013-07-09T00:14:35.160 に答える