Яка мета 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};
що повторює типи, і може бути дуже довгим.
Тип умовиводу працює в тому випадку, що 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
порівнянні 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 створює додаткову копію над прямим конструктором. Я завжди набираю свої пари, щоб надати простий синтаксис.
Це показує різницю (приклад Рампала Чадхарі):
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&>
цього, я зменшую кількість побудованих об'єктів, і лише коли я видаляю конструктор копій, я усуваю всі копії (очевидно). Після внесення обох цих змін мій результат включає в себе один виклик конструктору за замовчуванням і два виклики деструктора для того ж об’єкта. Я думаю, що мені щось треба бракувати. (г ++ 5.4.1, c ++ 11)
emplace
замість того, insert
якщо ви просто будуєте значення, яке потрібно вставити негайно (і ви не хочете зайвих примірників.) Це не моя область знань, якщо я можу навіть сказати, що у мене є, але копія / переміщення семантика, введена С ++ 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};
.