Std :: make_pair vs std :: pair'in kurucu amacı nedir?


Yanıtlar:


165

Fark, std::pairher iki öğenin türünü belirtmeniz gerektiğidir, oysa std::make_pairona söylemeniz gerekmeden, kendisine iletilen öğelerin türüyle bir çift oluşturacaktır. Zaten çeşitli belgelerden toplayabiliyordum.

Http://www.cplusplus.com/reference/std/utility/make_pair/ adresinden bu örneğe bakın.

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>

Örtük dönüşüm bonusunun yanı sıra, make_pair kullanmadıysanız yapmanız gerekir

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

birine atadığınız her seferinde zamanla sinir bozucu olurdu ...


1
Aslında, türler belirtmeye gerek kalmadan derleme zamanında çıkarılmalıdır.
Çad

@Tor Evet, ikisini de nasıl kullanacağımı biliyorum, bunun bir nedeni olup olmadığını merak ettim std::make_pair. Görünüşe göre sadece kolaylık sağlamak için.

@Jay Öyle görünüyor.
Tor Valamo

15
one = {10, 20}Bugünlerde yapabileceğinizi düşünüyorum ama kontrol etmek için kullanışlı bir C ++ 11 derleyici yok.
MSalters

6
Ayrıca make_pair, yapılar, birlikler, lambdalar ve diğer doodadlar dahil olmak üzere adsız türlerle çalıştığını unutmayın .
Mooing Duck

35

@MSalters yukarıda yanıtlandığı gibi, artık bunu C ++ 11'de yapmak için kıvırcık parantezleri kullanabilirsiniz (bunu sadece bir C ++ 11 derleyicisiyle doğrulayın):

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

28

C ++ 17'den önce sınıf şablonu bağımsız değişkenleri yapıcıdan çıkarılamadı

C ++ 17'den önce şöyle bir şey yazamazdınız:

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

çünkü şablon türlerini yapıcı argümanlarından çıkarır.

C ++ 17 sözdizimini mümkün kılar ve bu nedenle make_pairgereksizdir.

C ++ 17'den önce, std::make_pairdaha az ayrıntılı kod yazmamıza izin verdi:

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

daha ayrıntılı yerine:

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

hangi türleri tekrarlar ve çok uzun olabilir.

Yapımcı olmadığı için tür çıkarımı o C ++ 17 öncesi durumda çalışır make_pair.

make_pair aslında aşağıdakilere eşdeğerdir:

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

Aynı kavram insertervs için de geçerlidir insert_iterator.

Ayrıca bakınız:

Minimal örnek

İşleri daha somut hale getirmek için, sorunu en az şekilde gözlemleyebiliriz:

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

sonra:

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

mutlu bir şekilde derler, ancak:

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

ile başarısız:

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

ve bunun yerine çalışmak gerekir:

MyClass<int> my_class(1);

veya yardımcı:

auto my_class = make_my_class(1);

bir yapıcı yerine normal bir işlev kullanır.

Std :: reference_wrapper için fark

Bu yorum , kurucu std::make_pairyapmazken açılmasından bahsediyor std::reference_wrapper, bu yüzden bu bir fark. YAPILACAKLAR örneği.

GCC 8.1.0, Ubuntu 16.04 ile test edilmiştir .


1
"C ++ 17 sözdizimini mümkün kılar ve bu nedenle de_pair'i gereksiz kılar." - Neden std::make_pairC ++ 17'de kullanımdan kaldırılmadı?
andreee

@andreee emin değilim, olası bir neden sorun oluşturmaz bu yüzden eski kodu kırmaya gerek yok? Ama C ++ komite mantığına aşina değilim, bir şey bulursan bana ping at.
Ciro Santilli

1
Karşılaştığım kullanışlı bir şey, std :: make_pair <T1, T2> (o1, o2) ile türleri belirleyebilmenin, kullanıcının dolaylı olarak o1 veya o2 türlerini geçirme hatasını yapmasını engellemesidir. T1 veya T2'ye dökülür. Örneğin, imzalanmamış bir int'e negatif bir sayı iletmek. -Wsign-conversion -Werror c ++ 11'de std :: pair yapıcısı ile bu hatayı yakalamaz, ancak std :: make_pair kullanılırsa hatayı yakalar.
conchoecia

make_pairreferans paketleyicilerini açar, bu yüzden aslında CTAD'den farklıdır.
LF

26

make_pairYapıcıyı pairbelirtilen tür bağımsız değişkenleriyle kullanma ve açıkça çağırmak arasında bir fark yoktur . std::make_pairtürler ayrıntılı olduğunda daha kullanışlıdır, çünkü bir şablon yönteminde verilen parametrelere dayalı tür kesinti vardır. Örneğin,

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

Bunun C ++ şablon programlamasında yaygın bir deyim olduğunu belirtmek gerekir. Object Generator deyimi olarak bilinir, daha fazla bilgi ve güzel bir örnek burada bulabilirsiniz .

Düzenle Yorumlarda önerildiği gibi (kaldırıldığından beri), kopması durumunda aşağıdaki bağlantıdan biraz değiştirilmiş bir alıntıdır.

Bir Nesne Oluşturucu, türlerini açıkça belirtmeden nesnelerin oluşturulmasına izin verir. Sınıf şablonlarının sahip olmadığı işlev şablonlarının kullanışlı bir özelliğini temel alır: Bir işlev şablonunun tür parametreleri, gerçek parametrelerinden otomatik olarak çıkarılır. işlevin gerçek parametrelerine bağlı olarak şablonun std::make_pairbir örneğini döndüren basit bir örnektir .std::pairstd::make_pair

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

2
@duck Aslında &&C ++ 11'den beri.
Justme0

5

make_pair doğrudan kurucu üzerinden fazladan bir kopya oluşturur. Basit sözdizimi sağlamak için her zaman çiftlerimi yazıyorum.
Bu farkı gösterir (örnek Rampal Chaudhary tarafından):

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

4
Derleyicinin optimizasyon ayarları yeterince yüksekse, ekstra kopyanın her durumda eleneceğinden eminim.
Björn Pollex

1
Neden doğruluk için derleyici optimizasyonlarına güvenmek istediniz?
sjbx

Her iki sürümde de aynı sonuçları alıyorum ve std::movesadece içeride insertve / veya neye referans olacağı konusunda sample. Ben değiştirmek zaman sadece std::map<int,Sample>için std::map<int,Sample const&>ben inşa nesnelerin sayısını azaltmak olduğunu ve sadece ben tüm kopyaları (tabii ki) ortadan kaldırmak olduğunu kopya kurucu sildiğinizde. Bu değişikliklerin her ikisini de yaptıktan sonra, sonucum varsayılan yapıcıya bir çağrı ve aynı nesne için yıkıcıya iki çağrı içeriyor. Sanırım bir şey eksik olmalıyım. (g ++ 5.4.1, c ++ 11)
John P

FWIW Optimizasyon ve doğruluğun tamamen bağımsız olması gerektiğine katılıyorum, çünkü bu farklı optimizasyon seviyeleri tutarsız sonuçlar ürettikten sonra tam olarak bir sağlık kontrolü olarak yazdığınız kod türüdür. Genel olarak hemen eklemek için bir değer oluşturuyorsanız (ve fazladan örnek istemiyorsanız) emplacebunun yerine tavsiye ederim insert. Benim uzmanlık alanım değil, bir tane olduğunu söyleyebilirim, ancak kopyala / taşı C ++ 11 tarafından sunulan anlambilim bana çok yardımcı oldu.
John P

Aynı sorunla karşılaştığımı düşünüyorum ve tüm akşam boyunca hata ayıkladıktan sonra sonunda buraya geldim.
lllllllllllll

1

c ++ 11'den başlayarak sadece çiftler için tek tip başlatma kullanın. Bunun yerine:

std::make_pair(1, 2);

veya

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

sadece kullan

{1, 2};

{1, 2}bir çifti başlatmak için kullanılabilir, ancak tip çiftini taahhüt etmez. Yani otomatik kullanırken RHS: üzerinde bir tür taahhüt gerekir auto p = std::pair{"Tokyo"s, 9.00};.
Markus
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.