2012-03-09 11 views
68

-std = C++ 11を有効にして、g ++ 4.7(後のスナップショットの1つ)で再生していました。私は既存のコードベースの一部をコンパイルしようとしましたが、1つのケースはやや混乱しました。C++ 11指定されたテンプレートパラメータを持つmake_pairがコンパイルされない

誰かが何が起こっているのかを説明できるのであれば、私は感謝します。

ここで(私は種類を指定した場合、その後、私は同様に使用することがあります(3))私はmake_pairがであることを理解し、コード

#include <utility> 
#include <iostream> 
#include <vector> 
#include <string> 

int main () 
{ 
    std::string s = "abc"; 

    // 1 ok 
    std::pair < std::string, int > a = std::make_pair (s, 7); 

    // 2 error on the next line 
    std::pair < std::string, int > b = std::make_pair < std::string, int > (s, 7); 

    // 3 ok 
    std::pair < std::string, int > d = std::pair < std::string, int > (s, 7); 

    return 0; 
} 

は、(1)ケースとして使用されることをを意味します、しかし、この場合、なぜ失敗するのか分かりません。

正確なエラーがある:再び

test.cpp: In function ‘int main()’: test.cpp:11:83: error: no matching function for call to ‘make_pair(std::string&, int)’ test.cpp:11:83: note: candidate is: In file included from /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/utility:72:0, from test.cpp:1: /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5: note: template constexpr std::pair::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5: note: template argument deduction/substitution failed: test.cpp:11:83: note: cannot convert ‘s’ (type ‘std::string {aka std::basic_string}’) to type ‘std::basic_string&&’

、ここで問題は、単に「何が起こっているの?」ています私はテンプレート仕様を削除することで問題を解決できることを知っていますが、ここでは何が失敗しているのかを知りたいだけです。前もって感謝します。

EDIT:

  • グラム++ 4.4は問題なく、このコードをコンパイル。
  • -std = C++ 11の削除も問題なくコードでコンパイルされます。
+5

優れた質問です。 C++ 11の微妙な改変のもう1つの例は、[std :: vector'構造の改変](http://stackoverflow.com/questions/5759232/stdvector-default-construction-c11-そして改革 - 変化)。少なくともこの1つは、コンパイラエラーをもたらし、セマンティクスの静かな変更ではありません。 –

+1

私は整数変数iを持っています。私はiと別のオブジェクトとペアを作りたい。どのくらい私はmakepairを呼び出す必要があります。 1)make_pair <*i, obj> 2)int && j = i; make_pair ?両方とも動作していません。それを行う正しい方法は何ですか? – PHcoDer

答えて

108

これは、std::make_pairの使用を意図したものではありません。テンプレート引数を明示的に指定することは想定されていません。

C++ 11 std::make_pairTUテンプレート型パラメータであるタイプT&&U&&の二つの引数をとります。効果的に、それは(戻り値の型を無視して)次のようになります。

template <typename T, typename U> 
[return type] make_pair(T&& argT, U&& argU); 

あなたがstd::make_pairを呼び出して、明示的にテンプレート型引数を指定し、引数の控除は行われません。その代わりに型引数はテンプレート宣言に直接代入され、以下のようになります。

[return type] make_pair(std::string&& argT, int&& argU); 

これらのパラメータ型は両方とも参照値です。したがって、それらは右辺値にのみ結合できます。あなたが渡す2番目の引数のために、これはrvalue式なので、7は問題ではありません。ただし、sは左辺式です(一時的ではなく、移動されません)。つまり、関数テンプレートが引数と一致しないため、エラーが発生します。

したがって、TUがテンプレート引数リストに含まれていることを明示的に指定しないと、なぜ機能しますか?要するに、rvalue参照パラメータはテンプレートでは特殊です。部分的にの参照機能が無効になっていると呼ばれる言語機能のために、タイプA&&の右辺参照パラメータ(Aはテンプレートタイプパラメータ)は、Aの任意の種類にバインドできます。

Aは左辺値、右辺値、const修飾、揮発性の修飾、または非修飾であるかどうかを問題ではありませんAは、テンプレートパラメータそのものであり、唯一の場合ならば、A&&は、再び(そのオブジェクトにバインドすることができます)。あなたの例では

、我々は呼び出します。ここ

make_pair(s, 7) 

を、sはタイプstd::stringの左辺値であると7はタイプintの右辺値です。関数テンプレートのテンプレート引数を指定しないので、テンプレート引数の控除が実行され、引数の内容がわかります。 T&&からs、左辺値をバインドするに

は、コンパイラは、タイプstd::string& &&の引数を得、std::string&するTを推定します。しかし、参照への参照はありません。したがって、この「二重参照」は畳んでstd::string&になります。 sは一致します。

それはU&&7をバインドするために簡単です:コンパイラは右辺値であるため、7に正常にバインドタイプint&&のパラメータを、得intするUを推測することができます。

は、これらの新しい言語機能との機微がたくさんありますが、あなたは1つの単純なルールに従うならば、それは非常に簡単です:

If a template argument can be deduced from the function arguments, let it be deduced. Don't explicitly provide the argument unless you absolutely must.

Let the compiler do the hard work, and 99.9% of the time it'll be exactly what you wanted anyway. When it isn't what you wanted, you'll usually get a compilation error which is easy to identify and fix.

+6

これは非常によく包括的な説明です。ありがとうございました! – vmpstr

+1

@ジェームス - それは私が読むべき別の記事または答えからの "1つの単純なルール"ですか? –

+4

@MichaelBurr:いいえ、私はそれを作りました。 :-)それで、私はそれが本当だと思う!私はそれが本当だと思う...そのルールは私のためにほとんどすべての時間のために働く。 –

関連する問題