web-dev-qa-db-ja.com

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

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

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

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

162
user542687

違いは、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つに割り当てるたびに、それは時間の経過とともに迷惑になります...

147
Tor Valamo

上記の@MSaltersが回答したように、C++ 11で中括弧を使用してこれを行うことができます(C++ 11コンパイラでこれを検証しただけです)。

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

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));
25
devil

これが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);
}
21
mkm

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

c ++ 11以降では、ペアに対して均一な初期化を使用します。代わりに:

std::make_pair(1, 2);

または

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

ただ使う

{1, 2};
1
Mahmoud Badri