150

Mục đích của là std::make_pairgì?

Tại sao không làm std::pair<int, char>(0, 'a')?

Có sự khác biệt nào giữa hai phương pháp không?

|
137

Sự khác biệt là với std::pairbạn cần chỉ định loại của cả hai yếu tố, trong khi đó std::make_pairsẽ tạo ra một cặp với loại yếu tố được truyền cho nó, mà bạn không cần phải nói với nó. Đó là những gì tôi có thể thu thập từ nhiều tài liệu khác nhau.

Xem ví dụ này từ 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>

Ngoài phần thưởng chuyển đổi ngầm định của nó, nếu bạn không sử dụng make_ Pair bạn phải làm

one = pair<int,int>(10,20)

mỗi khi bạn được chỉ định cho một người, điều đó sẽ gây phiền nhiễu theo thời gian ...

|
29

Như @MSalters đã trả lời ở trên, bây giờ bạn có thể sử dụng dấu ngoặc nhọn để thực hiện điều này trong C ++ 11 (chỉ cần xác minh điều này với trình biên dịch C ++ 11):

pair<int, int> p = {1, 2};
|
25

Không có sự khác biệt giữa việc sử dụng make_pairvà gọi rõ ràng hàm pairtạo với các đối số kiểu đã chỉ định. std::make_pairsẽ thuận tiện hơn khi các kiểu dài dòng vì một phương thức mẫu có loại trừ dựa trên các tham số đã cho. Ví dụ,

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

Điều đáng chú ý là đây là một thành ngữ phổ biến trong lập trình mẫu C ++. Nó được gọi là thành ngữ Object Generator, bạn có thể tìm thêm thông tin và một ví dụ hay ở đây .

Chỉnh sửa Như ai đó đã đề xuất trong các nhận xét (kể từ khi xóa), phần sau đây là một trích xuất được sửa đổi một chút từ liên kết trong trường hợp nó bị hỏng.

Trình tạo đối tượng cho phép tạo các đối tượng mà không chỉ định rõ ràng các loại của chúng. Nó dựa trên một thuộc tính hữu ích của các mẫu hàm mà các mẫu lớp không có: Các tham số loại của mẫu hàm được tự động suy ra từ các tham số thực tế của nó. std::make_pairlà một ví dụ đơn giản trả về một thể hiện của std::pairmẫu tùy thuộc vào các tham số thực tế của std::make_pairhàm.

template <class T, class U>
std::pair <T, U> 
make_pair(T t, U u)
{
  return std::pair <T, U> (t,u);
}
|
16

Các đối số mẫu lớp không thể được suy ra từ hàm tạo trước C ++ 17

Trước C ++ 17, bạn không thể viết một cái gì đó như:

std::pair p(1, 'a');

vì điều đó sẽ suy ra các kiểu mẫu từ các đối số của hàm tạo.

C ++ 17 làm cho cú pháp đó có thể, và do đó make_pairdư thừa.

Trước C ++ 17, std::make_paircho phép chúng tôi viết mã dài ít hơn:

MyLongClassName1 o1();
MyLongClassName2 o2();
auto p = std::make_pair(o1, o2);

thay vì dài dòng hơn:

std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};

mà lặp đi lặp lại các loại, và có thể rất dài.

Kiểu suy luận hoạt động trong trường hợp tiền C ++ 17 đó vì make_pairkhông phải là hàm tạo.

make_pair về cơ bản là tương đương với:

template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
    return std::pair<T1, T2>(t1, t2);
}

Khái niệm tương tự áp dụng cho insertervs insert_iterator.

Xem thêm:

Ví dụ tối thiểu

Để làm cho mọi thứ cụ thể hơn, chúng ta có thể quan sát vấn đề tối thiểu với:

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);
}

sau đó:

g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp

vui vẻ biên dịch, nhưng:

g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp

thất bại với:

main.cpp: In function int main()’:
main.cpp:13:13: error: missing template arguments before my_class
     MyClass my_class(1);
             ^~~~~~~~

và yêu cầu thay vì làm việc:

MyClass<int> my_class(1);

hoặc người trợ giúp:

auto my_class = make_my_class(1);

trong đó sử dụng một hàm thông thường thay vì một hàm tạo.

Đã thử nghiệm với GCC 8.1.0, Ubuntu 16.04 .

|
  • 1

    "C ++ 17 làm cho cú pháp đó có thể, và do đó làm cho dự phòng trở nên dư thừa." - Tại sao nó std::make_pairkhông bị phản đối trong C ++ 17?

    – Ngô Mạnh Dũng 10:23:58 06/11/2018
  • 1

    @andreee Tôi không chắc, lý do có thể là nó không tạo ra rắc rối nên không cần phải phá mã cũ? Nhưng tôi không quen với lý do ủy ban C ++, hãy ping tôi nếu bạn tìm thấy thứ gì đó.

    – Lý Khánh Hà 10:51:00 06/11/2018
  • 1

    Một điều hữu ích mà tôi đã gặp là việc có thể chỉ định các loại với std :: make_ Pair <T1, T2> (o1, o2) ngăn người dùng mắc lỗi chuyển các loại o1 hoặc o2 mà không thể ngầm hiểu truyền tới T1 hoặc T2. Ví dụ, truyền một số âm cho một số nguyên không dấu. -Wsign-convert -Werror sẽ không bắt lỗi này với std :: cặp constructor trong c ++ 11 tuy nhiên nó sẽ bắt lỗi nếu sử dụng std :: make_ Pair.

    – Tạ Thanh Tùng 21:36:20 30/01/2019
4

make_ Pair tạo một bản sao bổ sung trên hàm tạo trực tiếp. Tôi luôn gõ các cặp của mình để cung cấp cú pháp đơn giản.
Điều này cho thấy sự khác biệt (ví dụ của 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;
}
|
  • 1

    Tôi khá chắc chắn rằng bản sao bổ sung sẽ bị xóa trong mọi trường hợp, nếu cài đặt tối ưu hóa của trình biên dịch đủ cao.

    – Huynh Phuonganh 13:00:52 19/02/2014
  • 1

    Tại sao bạn muốn dựa vào tối ưu hóa trình biên dịch cho chính xác?

    – Vũ Thành Nhân 08:46:57 02/12/2016
  • 1

    Tôi nhận được kết quả tương tự với cả hai phiên bản, và std::movechỉ bên trong insertvà / hoặc xung quanh những gì sẽ là một tài liệu tham khảo sample. Nó chỉ là khi tôi thay đổi std::map<int,Sample>để std::map<int,Sample const&>mà tôi giảm số lượng các đối tượng được xây dựng, và chỉ khi tôi xóa các constructor sao chép mà tôi loại bỏ tất cả các bản sao (rõ ràng). Sau khi thực hiện cả hai thay đổi đó, kết quả của tôi bao gồm một cuộc gọi đến hàm tạo mặc định và hai cuộc gọi đến hàm hủy cho cùng một đối tượng. Tôi nghĩ rằng tôi phải thiếu một cái gì đó. (g ++ 5.4.1, c ++ 11)

    – Tạ Việt Duy 23:13:24 30/08/2017
  • 1

    FWIW Tôi đồng ý rằng tối ưu hóa và tính chính xác phải hoàn toàn độc lập, vì đây chính xác là loại mã bạn viết dưới dạng kiểm tra vệ sinh sau khi các mức tối ưu hóa khác nhau tạo ra kết quả không nhất quán. Nói chung, tôi sẽ khuyên bạn emplacethay vì insertnếu bạn chỉ xây dựng một giá trị để chèn ngay lập tức (và bạn không muốn có thêm trường hợp.) Đó không phải là lĩnh vực chuyên môn của tôi, nếu tôi thậm chí có thể nói tôi có một, nhưng sao chép / di chuyển ngữ nghĩa được giới thiệu bởi C ++ 11 đã giúp tôi rất nhiều.

    – Ngô Trúc Phương 23:31:06 30/08/2017
0

bắt đầu từ c ++ 11 chỉ cần sử dụng khởi tạo thống nhất cho các cặp. Vì vậy, thay vì:

std::make_pair(1, 2);

hoặc là

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

chỉ dùng

{1, 2};
|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.