std :: make_pairとstd :: pairのコンストラクタの目的は何ですか?


180

の目的はstd::make_pair何ですか?

なぜしないのですstd::pair<int, char>(0, 'a')か?

2つの方法に違いはありますか?


6
C ++ 11では、make_pairがなくてもほぼ完全に実行できます。私の答えをください。
PlagueHammer 2014年

2
C ++ 17では、std::make_pair冗長です。これについて詳しく説明する以下の回答があります。
Drew Dormann、2018年

回答:


165

違いは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つに割り当てるたびに、時間が経つと煩わしくなります...


1
実際、型は指定する必要なしにコンパイル時に推定されるべきです。
チャド

@Torええ、私はそれらの両方を使用する方法を知っています、理由があるかどうか私はちょうど興味がありましたstd::make_pair。どうやら、それは単に便宜上のものです。

@ジェイそう見えます。
Tor Valamo 2012

15
今はできると思いますがone = {10, 20}、チェックするのに便利なC ++ 11コンパイラはありません。
MSalters 2012

6
またmake_pair、は、構造体、共用体、ラムダ、およびその他の不可解なものなど、名前のない型で動作することにも注意してください。
Mooing Duck、2015

35

@MSaltersが上記で返信したように、中かっこを使用してC ++ 11でこれを行うことができます(C ++ 11コンパイラでこれを確認しただけです)。

pair<int, int> p = {1, 2};

28

クラステンプレート引数は、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);
}

同じ概念がinsertervsにも適用され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);

コンストラクタの代わりに通常の関数を使用しています。

`std :: reference_wrapperの違い

このコメントは、コンストラクターがstd::make_pairアンラップstd::reference_wrapperしないのにアンラップすることを述べているので、それが1つの違いです。TODOの例。

GCC 8.1.0、Ubuntu 16.04でテスト済み。


1
「C ++ 17はその構文を可能にするため、make_pairは冗長になります。」std::make_pair-C ++ 17で非推奨にならないのはなぜですか?
andreee 2018年

@andreeeわからない、考えられる理由は問題が発生しないため古いコードを壊す必要がないということですか?しかし、私はC ++委員会の理論的根拠に精通していません。何かを見つけたらpingしてください。
Ciro Santilli郝海东冠状病六四事件法轮功

1
私が遭遇した便利なことの1つは、std :: make_pair <T1、T2>(o1、o2)でタイプを指定できることで、暗黙的にすることのできないタイプo1またはo2を渡すミスをユーザーが防ぐことができるということですT1またはT2にキャストします。たとえば、負数をunsigned intに渡します。-Wsign-conversion -Werrorは、c ++ 11のstd :: pairコンストラクターでこのエラーをキャッチしませんが、std :: make_pairが使用されている場合はエラーをキャッチします。
コンシェシア

make_pair参照ラッパーをアンラップするため、実際にはCTADとは異なります。
LF

26

型引数を指定しmake_pairpairコンストラクタを使用することと明示的に呼び出すことには違いはありません。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));

21

これはC ++テンプレートプログラミングにおける一般的なイディオムであることは注目に値します。これはオブジェクトジェネレーターイディオムとして知られています。詳細と良い例はここにあります

編集誰かがコメントで提案したように(削除されたため)、以下はリンクが壊れた場合に備えてリンクから少し変更した抜粋です。

オブジェクトジェネレーターでは、オブジェクトのタイプを明示的に指定せずにオブジェクトを作成できます。これは、クラステンプレートにはない、関数テンプレートの便利なプロパティに基づいています。関数テンプレートの型パラメーターは、実際のパラメーターから自動的に推定されます。関数の実際のパラメータに応じstd::make_pairstd::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);
}

2
@duck実際に&&はC ++ 11以降。
Justme0

5

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;
}

4
コンパイラーの最適化設定が十分に高ければ、余分なコピーはすべての場合に省略されると確信しています。
ビョルンポレックス2014

1
正確さを求めるためにコンパイラーの最適化に依存したくなるのはなぜですか?
sjbx

どちらのバージョンでも、への参照となるもののstd::move内部insertや周辺で同じ結果が得られsampleます。変更std::map<int,Sample>std::map<int,Sample const&>て初めて、構築されたオブジェクトの数を減らし、すべてのコピーを(明らかに)削除するのは、コピーコンストラクターを削除したときだけです。これらの両方の変更を行った後の結果には、デフォルトのコンストラクターへの1回の呼び出しと、同じオブジェクトのデストラクターへの2回の呼び出しが含まれています。私は何かを逃しているに違いないと思います。(g ++ 5.4.1、c ++ 11)
John P

FWIW最適化と正確性は完全に独立している必要があることに同意します。これは、さまざまな最適化レベルで一貫性のない結果が生成された後の、サニティチェックとして記述する種類のコードだからです。一般に、すぐに挿入する値を作成しているだけemplaceinsert場合(そして、追加のインスタンスが必要ない場合)の代わりにお勧めします。私が専門知識を持っているとは言えないかもしれませんが、コピー/移動C ++ 11によって導入されたセマンティクスは、私を大きく助けてくれました。
John P

私はまったく同じ問題に遭遇していると思いますし、夜中デバッグした後、ようやくここに来ました。
lllllllllllll

1

c ++ 11から始めて、ペアに対して統一された初期化を使用します。だから代わりに:

std::make_pair(1, 2);

または

std::pair<int, int>(1, 2);

ただ使う

{1, 2};

{1, 2}ペアを初期化するために使用できますが、タイプペアに対してはコミットしません。つまり、autoを使用するときは、RHSの型にコミットする必要があります auto p = std::pair{"Tokyo"s, 9.00};
マーカス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.