Какова цель std :: make_pair против конструктора std :: pair? - PullRequest
160 голосов
/ 14 февраля 2012

Какова цель std::make_pair?

Почему бы просто не сделать std::pair<int, char>(0, 'a')?

Есть ли разница между этими двумя методами?

Ответы [ 7 ]

145 голосов
/ 14 февраля 2012

Разница в том, что с 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)

каждый раз, когда вы назначаете один, что будет раздражать со временем ...

30 голосов
/ 24 февраля 2014

Как ответил @MSalters выше, теперь вы можете использовать фигурные скобки, чтобы сделать это в C ++ 11 (только что проверил это с помощью компилятора C ++ 11):

pair<int, int> p = {1, 2};
25 голосов
/ 14 февраля 2012

Нет разницы между использованием 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));
21 голосов
/ 15 марта 2013

Стоит отметить, что это распространенная идиома в программировании на C ++. Он известен как идиома 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);
}
20 голосов

Аргументы шаблона класса не могут быть выведены из конструктора до 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};

, который повторяет типы и может быть очень длинным.

Вывод типа работает в этом случае до C ++ 17, потому что make_pair не является конструктором.

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 против 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 .

4 голосов
/ 28 ноября 2013

make_pair создает дополнительную копию поверх прямого конструктора.Я всегда определяю свои пары, чтобы обеспечить простой синтаксис.
Это показывает разницу (пример Рампала Чаудхари):

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;
}
1 голос
/ 14 марта 2019

начиная с с ++ 11 просто используйте одинаковую инициализацию для пар. Так что вместо:

std::make_pair(1, 2);

или

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

просто используйте

{1, 2};
...