Apa tujuannya std::make_pair
?
Kenapa tidak lakukan saja std::pair<int, char>(0, 'a')
?
Apakah ada perbedaan antara kedua metode?
std::make_pair
berlebihan. Ada jawaban di bawah ini yang merinci ini.
Apa tujuannya std::make_pair
?
Kenapa tidak lakukan saja std::pair<int, char>(0, 'a')
?
Apakah ada perbedaan antara kedua metode?
std::make_pair
berlebihan. Ada jawaban di bawah ini yang merinci ini.
Jawaban:
Perbedaannya adalah bahwa dengan std::pair
Anda perlu menentukan jenis kedua elemen, sedangkan std::make_pair
akan membuat pasangan dengan jenis elemen yang diteruskan ke sana, tanpa Anda perlu mengatakannya. Itu yang bisa saya kumpulkan dari berbagai dokumen.
Lihat contoh ini dari 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>
Selain dari bonus konversi implisit, jika Anda tidak menggunakan make_pair, Anda harus melakukannya
one = pair<int,int>(10,20)
setiap kali Anda ditugaskan ke satu, yang akan mengganggu dari waktu ke waktu ...
std::make_pair
. Ternyata itu hanya untuk kenyamanan.
one = {10, 20}
saat ini tetapi saya tidak memiliki kompiler C ++ 11 yang berguna untuk memeriksanya.
make_pair
bekerja dengan jenis yang tidak disebutkan namanya, termasuk struct, serikat pekerja, lambdas, dan barang-barang kecil lainnya.
Seperti @MSalters menjawab di atas, Anda sekarang dapat menggunakan kurung kurawal untuk melakukan ini di C ++ 11 (cukup verifikasi ini dengan kompiler C ++ 11):
pair<int, int> p = {1, 2};
Argumen templat kelas tidak dapat disimpulkan dari konstruktor sebelum C ++ 17
Sebelum C ++ 17 Anda tidak dapat menulis sesuatu seperti:
std::pair p(1, 'a');
karena itu akan menyimpulkan tipe templat dari argumen konstruktor.
C ++ 17 membuat sintaks itu mungkin, dan karena itu make_pair
berlebihan.
Sebelum C ++ 17, std::make_pair
izinkan kami untuk menulis lebih sedikit kode verbose:
MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);
alih-alih yang lebih bertele-tele:
std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};
yang mengulang jenisnya, dan bisa sangat panjang.
Ketik inferensi berfungsi dalam kasus pra-C ++ 17 karena make_pair
bukan merupakan konstruktor.
make_pair
pada dasarnya setara dengan:
template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
return std::pair<T1, T2>(t1, t2);
}
Konsep yang sama berlaku untuk inserter
vs insert_iterator
.
Lihat juga:
Contoh minimal
Untuk membuat masalah lebih konkret, kita dapat mengamati masalah secara minimal dengan:
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);
}
kemudian:
g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp
mengkompilasi dengan senang hati, tetapi:
g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp
gagal dengan:
main.cpp: In function ‘int main()’:
main.cpp:13:13: error: missing template arguments before ‘my_class’
MyClass my_class(1);
^~~~~~~~
dan sebagai gantinya mengharuskan untuk bekerja:
MyClass<int> my_class(1);
atau pembantu:
auto my_class = make_my_class(1);
yang menggunakan fungsi biasa bukan konstruktor.
Perbedaan untuk `std :: reference_wrapper
Komentar ini menyebutkan bahwa std::make_pair
membukastd::reference_wrapper
sementara konstruktor tidak, jadi itu satu perbedaan. Contoh TODO.
Diuji dengan GCC 8.1.0, Ubuntu 16.04 .
std::make_pair
tidak usang di C ++ 17?
make_pair
membuka bungkus pembungkus referensi, jadi sebenarnya berbeda dari CTAD.
Tidak ada perbedaan antara menggunakan make_pair
dan secara eksplisit memanggil pair
konstruktor dengan argumen tipe tertentu. std::make_pair
lebih nyaman ketika jenis verbose karena metode templat memiliki tipe deduksi berdasarkan parameter yang diberikan. Sebagai contoh,
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));
Perlu dicatat bahwa ini adalah idiom umum dalam pemrograman template C ++. Ini dikenal sebagai idiom Object Generator, Anda dapat menemukan informasi lebih lanjut dan contoh yang bagus di sini .
Edit Seperti seseorang menyarankan dalam komentar (sejak dihapus) berikut ini adalah ekstrak yang sedikit dimodifikasi dari tautan jika rusak.
Object Generator memungkinkan pembuatan objek tanpa secara spesifik menentukan jenisnya. Ini didasarkan pada properti berguna templat fungsi yang tidak dimiliki templat kelas: Parameter tipe templat fungsi disimpulkan secara otomatis dari parameter aktualnya. std::make_pair
adalah contoh sederhana yang mengembalikan contoh std::pair
template tergantung pada parameter sebenarnya dari std::make_pair
fungsi.
template <class T, class U>
std::pair <T, U>
make_pair(T t, U u)
{
return std::pair <T, U> (t,u);
}
&&
sejak C ++ 11.
make_pair membuat salinan tambahan di atas konstruktor langsung. Saya selalu mengetikkan pasangan saya untuk memberikan sintaksis sederhana.
Ini menunjukkan perbedaan (contoh oleh 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
hanya di dalam insert
dan / atau sekitar apa yang akan menjadi referensi sample
. Hanya ketika saya mengubah std::map<int,Sample>
ke std::map<int,Sample const&>
saya mengurangi jumlah objek yang dibangun, dan hanya ketika saya menghapus copy constructor saya menghilangkan semua salinan (jelas). Setelah melakukan kedua perubahan tersebut, hasil saya mencakup satu panggilan ke konstruktor default dan dua panggilan ke destruktor untuk objek yang sama. Saya pikir saya pasti kehilangan sesuatu. (g ++ 5.4.1, c ++ 11)
emplace
alih-alih insert
jika Anda hanya membangun nilai untuk segera dimasukkan (dan Anda tidak ingin contoh tambahan.) Ini bukan bidang keahlian saya, jika saya dapat mengatakan saya memilikinya, tetapi salin / pindahkan semantik yang diperkenalkan oleh C ++ 11 telah banyak membantu saya.
mulai dari c ++ 11 cukup gunakan inisialisasi seragam untuk pasangan. Jadi alih-alih:
std::make_pair(1, 2);
atau
std::pair<int, int>(1, 2);
gunakan saja
{1, 2};
{1, 2}
dapat digunakan untuk menginisialisasi pasangan, tetapi tidak dilakukan untuk pasangan tipe. Yaitu ketika menggunakan auto Anda harus berkomitmen untuk tipe pada RHS: auto p = std::pair{"Tokyo"s, 9.00};
.