Какова цель std::make_pair
?
Почему бы просто не сделать std::pair<int, char>(0, 'a')
?
Есть ли разница между этими двумя методами?
std::make_pair
это избыточно. Ниже приведен ответ, который детализирует это.
Какова цель std::make_pair
?
Почему бы просто не сделать std::pair<int, char>(0, 'a')
?
Есть ли разница между этими двумя методами?
std::make_pair
это избыточно. Ниже приведен ответ, который детализирует это.
Ответы:
Разница в том, что 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)
каждый раз, когда вы назначаете один, что будет раздражать со временем ...
std::make_pair
. Видимо это просто для удобства.
one = {10, 20}
настоящее время, но у меня нет под рукой компилятора C ++ 11, чтобы проверить это.
make_pair
работает с безымянными типами, включая структуры, союзы, лямбды и другие дуды.
Как ответил @MSalters выше, теперь вы можете использовать фигурные скобки, чтобы сделать это в C ++ 11 (только что проверил это с помощью компилятора C ++ 11):
pair<int, int> p = {1, 2};
Аргументы шаблона класса не могут быть выведены из конструктора до 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);
который использует обычную функцию вместо конструктора.
Разница для `std :: reference_wrapper
Этот комментарий упоминает, что std::make_pair
разворачиваетstd::reference_wrapper
а конструктор - нет, так что это одно отличие. Пример TODO.
Протестировано с GCC 8.1.0, Ubuntu 16.04 .
std::make_pair
не стало устаревшим в C ++ 17?
make_pair
разворачивает справочные оболочки, поэтому на самом деле он отличается от CTAD.
Нет разницы между использованием 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, вы можете найти больше информации и хороший пример здесь .
редактировать Как кто-то предложил в комментариях (так как удалено), следующее является слегка измененной выдержкой из ссылки в случае ее разрыва.
Генератор объектов позволяет создавать объекты без явного указания их типов. Он основан на полезном свойстве шаблонов функций, которого нет в шаблонах классов: параметры типа шаблона функции автоматически определяются из его фактических параметров. 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 ++ 11.
make_pair создает дополнительную копию над прямым конструктором. Я всегда печатаю свои пары, чтобы обеспечить простой синтаксис.
Это показывает разницу (пример 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;
}
std::move
только внутри insert
и / или вокруг того, на что будет ссылаться sample
. Только когда я изменяю std::map<int,Sample>
на std::map<int,Sample const&>
это, я уменьшаю количество созданных объектов, и только когда я удаляю конструктор копирования, я удаляю все копии (очевидно). После внесения обоих этих изменений мой результат включает один вызов конструктора по умолчанию и два вызова деструктора для одного и того же объекта. Я думаю, что я что-то упускаю. (g ++ 5.4.1, c ++ 11)
emplace
вместо того, insert
чтобы просто создавать значение для немедленной вставки (и вам не нужны дополнительные экземпляры). Это не моя область знаний, если я могу даже сказать, что она у меня есть, а копирование / перемещение Семантика, представленная в C ++ 11, очень мне помогла.
начиная с c ++ 11 просто используйте равномерную инициализацию для пар. Так что вместо:
std::make_pair(1, 2);
или
std::pair<int, int>(1, 2);
просто используйте
{1, 2};
{1, 2}
может использоваться для инициализации пары, но не фиксирует тип пары. Т.е. при использовании авто вы должны взять на себя обязательство типа на РИТ: auto p = std::pair{"Tokyo"s, 9.00};
.