web-dev-qa-db-ja.com

透明なstd関数オブジェクトを使用する場合、空の山括弧を記述する必要がありますか?

クラステンプレート引数の推論を使用すると、次のように記述できます。

std::less Fn;

ただし、G ++ 8.2はこのコードを拒否します。

#include <algorithm>
#include <vector>
#include <functional>

int main()
{
std::vector v= { 1, 3, 2, 7, 5, 4 };

std::sort(v.begin(),v.end(),std::greater());
}

次のエラーを出力します:

error: cannot deduce template arguments for 'greater' from ()

Clang ++ 7.0およびMSVC 15.8.0は警告なしにコンパイルします。どのコンパイラが正しいですか?

34
metalfox

GCCが間違っています。 バグレポート が既にあります。

[dcl.type.simple]/2 言います:

type-specifierの形式typenameopt ネストされた名前指定子opt template-nameは、推定クラスタイプ([dcl.type.class.deduct])のプレースホルダーです。

そして [dcl.type.class.deduct]/2 はこう言います:

推定クラス型のプレースホルダーは、-type-specifier-seqnew-type-idまたはtype-idでも使用できます。 new-expressionas as simple-type-specifier as in explicit type conversion(functional notation)([ expr.type.conv])、またはtemplate-parameterparameter-declarationtype-specifierとして。推定されたクラスタイプのプレースホルダーは、他のコンテキストには表示されません。

そのような使用は許可されています。


[temp.arg]/4 は、構文エラーを説明しますtemplate-idが必要ですが、_<>_。ただし、ここでは_std::greater_はtemplate-idとして解決されないため、段落は適用されません。

28
xskxzr

ClangとMSVCは正しいです。 暗黙的に生成された推論ガイド(C++ 17以降) とデフォルトのテンプレート引数の組み合わせ効果のため、これは整形式でなければなりません。

(エンファシス鉱山)

関数スタイルのキャストまたは変数の宣言で、型指定子として引数リストのないプライマリクラステンプレートCの名前を使用する場合、推論は次のように進みます。

  • Cが定義されている場合、名前付きプライマリテンプレート(定義されている場合)で宣言されている各コンストラクター(またはコンストラクターテンプレート)Ciに対して、架空の関数テンプレートFiが構築されます。
    • fiのテンプレートパラメーターは、Cのテンプレートパラメーター(Ciがコンストラクターテンプレートの場合)に続いてCiのテンプレートパラメーターです(デフォルトのテンプレート引数も含まれます
    • fiの関数パラメーターはコンストラクターパラメーターです
    • fiの戻り型はCで、その後に<>で囲まれたクラステンプレートのテンプレートパラメータが続きます
  • Cが定義されていないか、コンストラクターを宣言していない場合、架空のコンストラクターC()から上記のように導出された架空の関数テンプレートが追加されます
  • いずれの場合でも、上記のように仮想コンストラクタC(C))から派生した架空の関数テンプレートが追加されます。これはコピー演de候補と呼ばれます。

テンプレート引数の推論とオーバーロードの解決は、オーバーロードセットを形成する目的でコンストラクターのシグネチャがガイド(リターンタイプを除く)と一致する架空のクラスタイプの架空のオブジェクトの初期化のために実行され、初期化子はどのクラステンプレート引数の推定が実行されたか、ただし、初期化リストがタイプ(おそらくcv修飾)Uの単一の式で構成される場合、初期化リストの初期化(初期化リストコンストラクタを考慮)の最初のフェーズは省略されます。 CまたはCの特殊化から派生したクラス.

これらの架空のコンストラクターは、仮想クラス型のパブリックメンバーです。ガイドが明示的なコンストラクターから作成された場合、それらは明示的です。オーバーロード解決が失敗した場合、プログラムの形式は正しくありません。それ以外の場合、選択したFテンプレート特殊化の戻り値の型は、推定クラステンプレート特殊化になります。

std::greater()を指定すると、暗黙的に生成された演guideガイドが適用され、追加の架空の関数が最後に選択されます。オーバーロード解決の結果として、デフォルト引数voidが適用され、推定される型はvoidになります。つまり、std::greater()は、std::greater<void>()またはstd::greater<>()と同じことを意味します。


ところで:Gccはstd::greater()ではコンパイルできませんが、std::greater{}またはstd::greater g;は問題ありません。gccのバグかもしれません。

14
songyuanyao