2017-09-01 3 views
20

std::vectorの控除ガイドについては、cppreferenceを使用しています。C++ 17のstd :: vector deductionガイドは何ですか?

例:

#include <vector> 

int main() { 
    std::vector<int> v = {1, 2, 3, 4}; 
    std::vector x{v.begin(), v.end()}; // uses explicit deduction guide 
} 

だから、私はそれについていくつか質問がある:

  • C++ 17でstd::vector控除ガイドとは何ですか?

  • なぜ、いつベクトル減算が必要ですか?ここで

  • は、xstd::vector<int>またはstd::vector<std::vector<int>>ですか?

+3

'X'は、おそらく 'のstd ::ベクトル<はstd ::ベクトル ::イテレータ>'です。 –

+0

見るためのxに値を追加してください:[デモ](http://coliru.stacked-crooked.com/a/640910c60c5735c1)ので 'のstd ::ベクトル<はstd ::ベクトル ::イテレータ>'。 – Jarod42

+0

一般的に控除ガイドは何ですか?そうでない場合は、[this](http://en.cppreference.com/w/cpp/language/class_template_argument_deduction#User-defined_deduction_guides)が役立つ可能性があります。 – HolyBlackCat

答えて

17

What are std::vector deduction guides in C++17?

ユーザ定義の控除ガイドは、ユーザーがclass template argument deductionは、そのコンストラクタの引数からテンプレートクラスの引数を推論する方法を決定することができます。この場合、std::vectorには、イテレータペアからの構築をより直観的にする明示的なガイドがあるようです。


Why and when do we need vector deduction?

我々はそれを「必要」はありませんが、それは一般的なコードの中や非常に明白だコードに有用である(明示的にテンプレート引数を指定すなわちコードは、読者に有益ではありません) 。定義せずにテンプレート関数の宣言を書いて、それを呼び出そうと -


Is x a vector<int> or a vector<vector<int>> ?

はここですぐにこれを理解するにはすてきなトリックです。コンパイラは渡された引数の型を出力します。 std::vector<std::vector<int>::iterator>に推定される

template <typename> 
void foo(); 

// ... 

foo(x); 

error: no matching function for call to foo(std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> > ...

エラーメッセージ、xから見ることができるように:ここでは何グラム++ 8枚のプリントアウトです。


Why?

std::vectorの控除はare available on cppreference.orgを案内します。標準イテレータ対からの明示的な控除ガイドを定義するように思われる:

enter image description here

グラム++ 8に遭遇する現象は関係なく、正しいと思われる、

  • overload resolution prefers the constructor with std::initializer_list with the braced initializer list

  • other constructors are considered only after all std::initializer_list constructors have been tried in list-initialization

std:vector<std::vector<int>::iterator>Rakete1111を引用)としてしたがって、リスト初期化を使用すると正しい結果になります。 live example

xstd::vector x(v.begin(), v.end())で構成するとき、代わりにintが推定されます。live example

+4

あなたの最後のポイントは半分に過ぎません。控除ガイドがない場合でも、型は 'std:vector :: iterator>'になります。オーバーロードの解決は、初期化子リストを括弧で囲んで 'std :: initializer_list'を使ってコンストラクタを優先するからです。 – Rakete1111

+0

@ Rakete1111これは、cppreferenceの例が示唆しているものではありません - 例が正しいかどうかわかりませんが、ユーザー定義の控除ガイドが自動的な控除ガイドよりも優先されることがあります。 【最高の生存関数(http://en.cppreference.com/w/cpp/language/overload_resolution#Best_viable_function)「によればRakete1111 @ – Holt

+0

6)、または、F1は、ユーザ定義の控除から生成されていないという場合ガイドとF2はそうではありません」と、推論ガイド付きのコンストラクタが過負荷解決に適していることを意味すると思います。 – songyuanyao

5

What are std::vector deduction guides in C++17?

Class template argument deduction指定:「クラステンプレートをインスタンス化するためには、すべてのテンプレート引数は、すべてのテンプレート引数を指定する必要があります知られてではなく、しなければなりません。」

これはstd:vectorにローカライズされています。つまり、std:vectorは単なるクラスです。特別なことは何もない。ここで

は、参考文献からstd::vector deducationガイドです:

template< class InputIt, 
      class Alloc = std::allocator<typename std::iterator_traits<InputIt>::value_type>> 
vector(InputIt, InputIt, Alloc = Alloc()) 
    -> vector<typename std::iterator_traits<InputIt>::value_type, Alloc>; 

ときからタイプの控除あなたは構文に慣れていない場合は、What are template deduction guides in C++17?

Why and when do we need vector deduction?

をお読みくださいあなたがガイドを必要とします引数は、それらの引数の1つの型に基づいていません。

Is x a vector<int> or a vector<vector<int>> ?

どちらもありません。

それは次のとおりです(例えばxに番号を割り当てることによって)、簡単なコンパイルエラーを強制

std::vector<std::vector<int>::iterator> 

)その型を発表する:

error: no match for 'operator=' (operand types are 'std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, std::allocator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > > >' and 'int') 

PS:

Why do we need that initialization, Alloc = Alloc() in that guide?

T hatのデフォルトの引数は、アロケータで渡すことができます。デフォルト設定では、2つのガイドは必要ありません。

+2

なぜ、そのガイドでその初期化、 'Alloc = Alloc()'が必要なのでしょうか? 'Alloc'は型自体を表現するのに十分ですか? –

+0

@DeanSeoデフォルトの引数です。 – Barry

+0

@Barry Right。しかし、控除ガイドから必要なのは議論ではなくタイプである。コンパイラは既に、* Alloc()*を使わないでその_default_型を知っていますか? –

7

Here, Is x a std::vector<int> or a std::vector<std::vector<int>> ?

その他の質問には他の回答がありますが、もう少し詳しく説明したいと思います。クラステンプレートの引数の控除を実行するときは、コンストラクタからsynthesize a bunch of function templates、次にdeduction guidesからいくつかを取得し、オーバーロード解決を実行して正しいテンプレートパラメータを決定します。

std::vector<T,A>にはかなりのコンストラクタがありますが、そのほとんどにはTは記載されていません。これはTを推測できないコンテキストにするため、このオーバーロードで実行可能なオプションではありません。それらがある

template <class InputIt> 
vector<typename std::iterator_traits<InputIt>::value_type> __f(InputIt, InputIt); 

:アロケータをドロップすることで、私も簡素化しますまた、その後

template <class T> vector<T> __f(size_t, T const&); // #2 
template <class T> vector<T> __f(vector<T> const&); // #5 
template <class T> vector<T> __f(vector<T>&&);   // #6, NB this is an rvalue ref 
template <class T> vector<T> __f(initializer_list<T>); // #8 

そしてこのdeduction guide、:我々は場合にのみ実行可能かもしれないものを使用するように設定を事前にプルーン私たちの5人の候補者は、[dcl.init]のように、__f({v.begin(), v.end()})経由のコールをオーバーロードしています。これはリストの初期化であるため、start with the initializer_list candidatesが存在しない場合にのみ、他の候補に進む。この場合、実行可能な候補(#8)はinitializer_listなので、他の候補も考慮せずに選択します。その候補はstd::vector<int>::iteratorとしてT推測するので、私たちはその後、std::vector<std::vector<int>::iterator>リスト初期化2回の反復子とのコンストラクタを選択するために、オーバーロードの解決のプロセスを再起動します。

これはおそらく望ましい結果ではありません - 私たちは、おそらくvector<int>を望んでいました。そこに解決策は単純です:()の使用:

std::vector x(v.begin(), v.end()); // uses explicit deduction guide 

initializer_list候補者が実行可能な候補ではないので、我々はリストの初期化を行っていません。結果として、控除ガイド(唯一の実行可能な候補)を介してvector<int>を推論し、そのイテレータ対のコンストラクタを呼び出すことになります。これには実際にコメントを修正することの副次的な利点があります。


これは{}を初期化する()で初期化するよりも乱暴に異なる何かをする多くの場所の一つです。いくつかは、{}が均一な初期化であると主張しています。私の経験則:具体的には{}を使用してください。意識的には、{}が提供する動作が必要です。それ以外の場合は()です。

関連する問題