มีจุดประสงค์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
ทำงานได้กับประเภทที่ไม่มีชื่อรวมถึง struct, unions, lambdas และ doodads อื่น ๆ
ดังที่ @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
อนุญาตให้เราเขียนโค้ด verbose น้อยกว่า:
MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);
แทน verbose เพิ่มเติม:
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);
}
แนวคิดเดียวกันกับVSinserter
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
ในขณะที่ตัวสร้างไม่ได้ดังนั้นจึงเป็นข้อแตกต่าง ตัวอย่างสิ่งที่ต้องทำ
ทดสอบกับGCC 8.1.0, อูบุนตู 16.04
std::make_pair
ไม่เลิกใช้ใน C ++ 17
make_pair
ไม่ทำการรวม wrappers อ้างอิงดังนั้นจึงแตกต่างจาก CTAD จริง ๆ
ไม่มีความแตกต่างระหว่างการใช้make_pair
และการเรียกคอนpair
สตรัคเตอร์อย่างชัดเจนด้วยอาร์กิวเมนต์ชนิดที่ระบุ std::make_pair
สะดวกยิ่งขึ้นเมื่อชนิดเป็น verbose เนื่องจากวิธีการแม่แบบมีการหักประเภทตามพารามิเตอร์ที่กำหนด ตัวอย่างเช่น,
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 ++ เป็นที่รู้จักกันเป็นวัตถุปั่นไฟสำนวนคุณสามารถหาข้อมูลเพิ่มเติมและตัวอย่างที่ดีที่นี่
แก้ไขตามที่มีคนแนะนำในความคิดเห็น (ตั้งแต่ลบ) ต่อไปนี้เป็นสารสกัดที่แก้ไขเล็กน้อยจากลิงค์ในกรณีที่มันแตก
เครื่องสร้างวัตถุช่วยให้การสร้างวัตถุโดยไม่ต้องระบุประเภทของพวกเขาอย่างชัดเจน มันขึ้นอยู่กับคุณสมบัติที่มีประโยชน์ของฟังก์ชั่นเทมเพลตซึ่งเทมเพลตของคลาสไม่มี: พารามิเตอร์ประเภทของเทมเพลตฟังก์ชั่นนั้นจะถูกอนุมานโดยอัตโนมัติจากพารามิเตอร์จริง 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&>
ฉันลดจำนวนของวัตถุที่สร้างและเฉพาะเมื่อฉันลบตัวสร้างสำเนาที่ฉันกำจัดสำเนาทั้งหมด (ชัด) หลังจากทำการเปลี่ยนแปลงทั้งสองอย่างแล้วผลลัพธ์ของฉันจะรวมการเรียกหนึ่งไปยังตัวสร้างเริ่มต้นและการเรียกสองครั้งไปยัง destructor สำหรับวัตถุเดียวกัน ฉันคิดว่าฉันต้องคิดถึงบางสิ่งบางอย่าง (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}
สามารถใช้ในการเริ่มต้นคู่ แต่ไม่ได้กระทำสำหรับคู่ประเภท กล่าวคือเมื่อมีการใช้รถยนต์ที่คุณต้องกระทำเพื่อประเภทใน RHS auto p = std::pair{"Tokyo"s, 9.00};
นี้: