std::make_pair
の目的は何ですか?
なぜstd::pair<int, char>(0, 'a')
しないのですか?
2つの方法に違いはありますか?
違いは、std::pair
では両方の要素のタイプを指定する必要がありますが、std::make_pair
は渡された要素のタイプとペアを作成するため、通知する必要はありません。とにかくそれはさまざまなドキュメントから収集できるものです。
http://www.cplusplus.com/reference/std/utility/make_pair/ からこの例を参照してください
pair <int,int> one;
pair <int,int> two;
one = make_pair (10,20);
two = make_pair (10.5,'A'); // ok: implicit conversion from pair<double,char>
暗黙的な変換ボーナスは別として、make_pairを使用しなかった場合は、実行する必要があります。
one = pair<int,int>(10,20)
あなたが1つに割り当てるたびに、それは時間の経過とともに迷惑になります...
上記の@MSaltersが回答したように、C++ 11で中括弧を使用してこれを行うことができます(C++ 11コンパイラでこれを検証しただけです)。
pair<int, int> p = {1, 2};
make_pair
を使用することと、指定された型引数でpair
コンストラクターを明示的に呼び出すこととの間に違いはありません。 std::make_pair
は、型が冗長な場合に便利です。テンプレートメソッドには、指定されたパラメーターに基づいて型の推論があるためです。例えば、
std::vector< std::pair< std::vector<int>, std::vector<int> > > vecOfPair;
std::vector<int> emptyV;
// shorter
vecOfPair.Push_back(std::make_pair(emptyV, emptyV));
// longer
vecOfPair.Push_back(std::pair< std::vector<int>, std::vector<int> >(emptyV, emptyV));
これがC++テンプレートプログラミングの一般的なイディオムであることは注目に値します。 Object Generatorイディオムとして知られています。詳細とニースの例 here を見つけることができます。
Edit誰かがコメントで示唆したように(削除されたため)、以下はリンクが壊れた場合のリンクからのわずかに変更された抜粋です。
Object Generatorを使用すると、タイプを明示的に指定せずにオブジェクトを作成できます。これは、クラステンプレートにはない関数テンプレートの有用なプロパティに基づいています。関数テンプレートの型パラメーターは、実際のパラメーターから自動的に推定されます。 std::make_pair
は、std::pair
関数の実際のパラメーターに応じてstd::make_pair
テンプレートのインスタンスを返す簡単な例です。
template <class T, class U>
std::pair <T, U>
make_pair(T t, U u)
{
return std::pair <T, U> (t,u);
}
C++ 17の前にコンストラクタからクラステンプレート引数を推測できませんでした
C++ 17より前は、次のような記述ができませんでした。
std::pair p(1, 'a');
コンストラクターの引数からテンプレートタイプを推測するためです。
C++ 17はその構文を可能にするため、make_pair
冗長です。
C++ 17より前は、std::make_pair
により、より冗長なコードを記述できました。
MyLongClassName1 o1();
MyLongClassName2 o2();
auto p = std::make_pair(o1, o2);
より冗長ではなく:
std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};
タイプが繰り返され、非常に長くなる可能性があります。
make_pair
はコンストラクタではないため、C++ 17より前のケースでは型推論が機能します。
make_pair
は基本的に次と同等です。
template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
return std::pair<T1, T2>(t1, t2);
}
同じ概念がinserter
vs insert_iterator
にも適用されます。
こちらもご覧ください:
最小限の例
物事をより具体的にするために、次の方法で問題を最小限に観察できます。
main.cpp
template <class MyType>
struct MyClass {
MyType i;
MyClass(MyType i) : i(i) {}
};
template<class MyType>
MyClass<MyType> make_my_class(MyType i) {
return MyClass<MyType>(i);
}
int main() {
MyClass<int> my_class(1);
}
その後:
g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp
コンパイルは成功しますが、次のとおりです。
g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp
失敗します:
main.cpp: In function ‘int main()’:
main.cpp:13:13: error: missing template arguments before ‘my_class’
MyClass my_class(1);
^~~~~~~~
代わりに動作する必要があります:
MyClass<int> my_class(1);
またはヘルパー:
auto my_class = make_my_class(1);
コンストラクタの代わりに通常の関数を使用します。
GCC 8.1.0、Ubuntu 16.04 でテスト済み。
make_pairは、直接コンストラクターに追加のコピーを作成します。単純な構文を提供するために、常にペアをtypedefします。
これは違いを示しています(Rampal Chaudharyの例):
class Sample
{
static int _noOfObjects;
int _objectNo;
public:
Sample() :
_objectNo( _noOfObjects++ )
{
std::cout<<"Inside default constructor of object "<<_objectNo<<std::endl;
}
Sample( const Sample& sample) :
_objectNo( _noOfObjects++ )
{
std::cout<<"Inside copy constructor of object "<<_objectNo<<std::endl;
}
~Sample()
{
std::cout<<"Destroying object "<<_objectNo<<std::endl;
}
};
int Sample::_noOfObjects = 0;
int main(int argc, char* argv[])
{
Sample sample;
std::map<int,Sample> map;
map.insert( std::make_pair( 1, sample) );
//map.insert( std::pair<int,Sample>( 1, sample) );
return 0;
}
c ++ 11以降では、ペアに対して均一な初期化を使用します。代わりに:
std::make_pair(1, 2);
または
std::pair<int, int>(1, 2);
ただ使う
{1, 2};