Nima uchun sinf shabloni asoschilari argumentlari avtomatik ravishda aniqlanmagan?

Quyidagi sinfga e'tibor bering:

template
class Pair
{
     public:
         T1 First;
         T2 Second;
         Pair(const T1 &First, const T2 &Second) : First(First), Second(Second) { }
}

C ++ da quyidagilarga ruxsat berilmaydi:

auto p = Pair(10, 10);

Nima uchun ruxsat berilmadi? turlari konstruktiv chaqiruvdan to'liq aniqlanishi mumkin Buning uchun vaqtinchalik echim borligini bilaman:

template
Pair MakePair(const T1 &First, const T2 &Second)
{
    return Pair(First, Second);
}

Lekin nima uchun bu kerak? Nima uchun derleyici faqat shablonni bajaradigan kabi argumentlardan turini aniqlamaydi? Buning sababi, uning standarti bunga ruxsat bermaydi, shuning uchun standart nima uchun ruxsat bermaydi?

Tartibga solish:
Buni, nima uchun bunga yo'l qo'ymaslik kerak, deganlar uchun:

template
class Pair
{
     public:
         T1 First;
         T2 Second;
         Pair(const T1 &First, const T2 &Second) : First(First), Second(Second) { }
         Pair(const T2 &Second, const T1 &First) : First(First), Second(Second) { }
};

auto p = Pair(10,1.0);

Buni shablonlarni ortiqcha yuklamoq bilan bajarish mumkin:

template
Pair MakePair(const T1 &First, const T2 &Second)
{
    return Pair(First, Second);
}
template
Pair MakePair(const T2 &Second, const T1 &First)
{
    return Pair(First, Second);
}

Nima uchun bu funktsiyalar uchun ruxsat beriladi, lekin sinflar uchun emas?

13
@GeneBushuyev: Siz sinfni "chaqirish" orqali konstruktorni xohlashingizni bildirasiz.
qo'shib qo'ydi muallif Dani, manba
So'ngra ikkala MakePair ilovalari bir-biriga o'xshash emas, siz ularni yozishingiz mumkin, lekin derleyici eng yaxshi ortiqcha yukni topa olmagani kabi, funksiya shablonini uchun turlarni belgilashingiz kerak bo'ladi.
qo'shib qo'ydi muallif David Rodríguez - dribeas, manba
Men buni shablonlarni haddan tashqari yuklagan holda bajarishim mumkin: Aslida, xuddi shu sabablarga ko'ra yo'q. Bu noaniq. codepad.org/axjCAZyL
qo'shib qo'ydi muallif Mooing Duck, manba
@Mooing: O'ylaymanki, u shunchaki shubhali argumentlarni aniqlash kerak, bunga asosan konstruktorni haddan tashqari yuklab olish vazifasi yuklanganligi bilan bir xil funktsiyalarni yaratishi mumkin.
qo'shib qo'ydi muallif Benjamin Lindley, manba
chunki quruvchilarning nomlari yo'q va ularni chaqirish mumkin emas, dalillarni bekor qilish faqat funktsiya chaqiruvlari uchun ishlaydi.
qo'shib qo'ydi muallif Gene Bushuyev, manba

3 javoblar

Bjarne Stroustrup bu masala xususida shunday deb aytishi kerak:

Sinf shablonini argumentlari hech qachon chiqarilmasligini unutmang. Buning sababi   bir sinf uchun bir necha konstruktorlar taqdim etgan moslashuvchanlikni   ko'p hollarda bunday cheklashni amalga oshirish mumkin emas va ko'pchilikda g'ayrioddiy   batafsilroq.

10
qo'shib qo'ydi
Funktsiya shablonini haddan tashqari yuklab olish haqida ham bir narsa aytish mumkin
qo'shib qo'ydi muallif Dani, manba
O'zgartirishga misol qo'shildi
qo'shib qo'ydi muallif Dani, manba
Turli xil funktsiya shablonini haddan tashqari yuklab olish bilan yaratilgan turdagi noaniqlik mavjud emas, chunki hech qanday turdagi yaratilmaydi. Yuqorida keltirilgan so'zlar yaxshi emas, ammo umid qilamanki, siz mening ma'numni olasizmi?
qo'shib qo'ydi muallif John Dibling, manba
Ko'p vaqt oldin auto birinchi marta kiritilganda, men ushbu sintaksisdan ctors argumentini bekor qilish uchun, masalan, juftlik (10,10) . o'rniga mypair p (10,10) yozishi uchun , mypair = juftlik dan foydalangan holda auto p = maksimallash (10,10); . Ushbu sintaksisi yordamchi funktsiyalarni make_something() (kerakli turdagi tulovlardan boshqa maqsadga xizmat qilmaydi) qilish kerak edi.
qo'shib qo'ydi muallif Gene Bushuyev, manba

Quyidagilarga e'tibor bering.

template
class Pair
{
     public:
         T1 First;
         T2 Second;
         Pair(const T1 &First, const T2 &Second) : First(First), Second(Second) { }
         Pair(const T2 &Second, const T1 &First) : First(First), Second(Second) { }
};

auto p = Pair(10,1.0);

Should p be a Pair or a Pair?

5
qo'shib qo'ydi
@David: Lekin agar bu noaniq bo'lsa, nima uchun ruxsat berilmaydi? Siz aytdingizmi, chunki u noaniq bo'lishi mumkin, shuning uchun ham men bir-biridan farq qiladigan funksiyalarning misolini keltirdim, lekin umumiy holatda vazifalarda, lekin umumiy holda sinflarda emas.
qo'shib qo'ydi muallif Dani, manba
O'zgartirishga misol qo'shildi
qo'shib qo'ydi muallif Dani, manba
Xuddi shu narsa funksiyaning shablonini haddan tashqari yuklab olish bilan amalga oshirilishi mumkin.
qo'shib qo'ydi muallif Dani, manba
@Benjamin: Chunki bu noxush narsa emas.
qo'shib qo'ydi muallif John Dibling, manba
@Dani, umumiy xususiyatlar o'chirildi, chunki ular qo'shilgan qiymat qo'shimcha komplekslikni kompilyator yoki foydalanuvchi dasturlarida qoplamaydi. std :: min (10, 5.0) turini nima ekanligini bilasizmi (derleyici foydalanmasdan)?
qo'shib qo'ydi muallif David Rodríguez - dribeas, manba
@Dani: Qo'shimcha misol (ikkita MakePair ) noaniq. Uni yozishingiz mumkin bo'lsa, ularni qo'lda ko'rsatmasdan qo'ng'iroq qila olmaysiz va bu o'z navbatida siz bir qadam oldingiz: bundaylarni aniq qilishni anglatadi.
qo'shib qo'ydi muallif David Rodríguez - dribeas, manba
@BenjaminLindley: hozirgacha ushbu sahifadagi barcha kodlarda Pair () ikki xil funktsiyaga mos keladi. turlari bir-biridan farq qilmaydi, funktsiyalar bo'ladi.
qo'shib qo'ydi muallif Mooing Duck, manba
Er, oops. Pair (10, 10.0) ikkala kodga mos keladi: Pair :: Pair (const T1 & First, const T2 & Second) va Pair :: Pair (const T2 & Second, const T1 & Birinchi) . MakePair (10,10,0) kodi MakePair (const T1 & First, const T2 & Second) va MakePair (const T2 & Second, const T1 & First) , shuning uchun hamma holatlarda qo'ng'iroqlar noaniq.
qo'shib qo'ydi muallif Mooing Duck, manba
Oh, OPning original sinfida, noaniqlik yo'q. Men til uslubchisi buni man qilganligi sababini o'ylay olmayman. Bjarne Stroustrupning taklifi aslida juda ko'p sabab emas.
qo'shib qo'ydi muallif Mooing Duck, manba
@Dani: Men sizning fikringizni ko'raman. Nima uchun u bir xil bo'lgan holatlarda turlarini aniqlay olmaydi? Buni o'ylashim kerak.
qo'shib qo'ydi muallif Benjamin Lindley, manba
@John: Agar men sinfdoshimga o'xshab ortiqcha yuk yo'q bo'lsa, men hech qanday ixtisoslashmaganman, qanday qilib bu noaniq?
qo'shib qo'ydi muallif Benjamin Lindley, manba
IOW, Pair (10,10.0) bilan bir qatorda Pair (10,10.0) nima bo'lishi mumkin?
qo'shib qo'ydi muallif Benjamin Lindley, manba
@Mooing Duck: Men sizni kuzatmayapman. Bu sahifadagi barcha kodlarda shu kungacha Pire () hech narsaga mos kelmaydi, chunki mening sinfim ham, Danining ham standart konstruktor yo'q.
qo'shib qo'ydi muallif Benjamin Lindley, manba
@Mooing: Lekin men hech qanday Pair :: Pair (const T2 & Second, const T1 & First) bo'lmasa, u erda noaniqlik mavjud bo'lmagan OPning original sinfiga ishora qilyapmanmi?
qo'shib qo'ydi muallif Benjamin Lindley, manba
@Dani: Qanday qilib?
qo'shib qo'ydi muallif Benjamin Lindley, manba

Ko'pincha odatda yaxshiroq emas. Agar tizimni ishlab chiqish kerak bo'lganda, siz turli funktsiyalar qanday ta'sir qilishiga ehtiyot bo'lishingiz kerak va foydalanuvchilar uchun eng qulay echimni tanlashingiz kerak. Odatda savollar foydalanuvchilarga nimani taklif qiladi , xususiyat nimani talab qiladigan va nima xususiyatlar keltirishi mumkin .

Bunday holatda, turdagi chegirmalarni berish sizga o'zgarmaydiganni e'lon qilishda yoki konstruktorni to'g'ridan-to'g'ri chaqirganda bunday turdagi ma'lumotlarni berishni o'tkazib yuborishga yordam beradi:

pair p = pair( 10, 20 );

Argumentlar deklaratsiyasi auto bilan amalga oshirilishi mumkin, shuning uchun u endi muammo emas, lekin bu xususiyatning sababli sababi bo'lishi mumkin. Konstruktor chaqiruvida qo'shilgan qiymat juda cheklangan bo'lsa, siz standart kutubxonada bo'lgani kabi, deb nomlangan konstruktorni bilan ta'minlashingiz mumkin:

auto p = make_pair( 10, 20 );

Shunday qilib, kunning oxirida, konstruktorni to'g'ridan-to'g'ri chaqirishi mumkin bo'lgan qo'shimcha qiymat aslida cheklangan, chunki siz har doim siz uchun obyektni yaratadigan nomlangan funksiyani taqdim eta olasiz. Mumkin bo'lgan qo'shimcha nusxalar optimallashtirildi, shuning uchun to'g'ridan-to'g'ri konstruktorni juftlik (10,20) ni chaqirgan holda make_pair

Endi, bu xususiyatning foydalanuvchi kodida bo'lishi mumkin bo'lgan salbiy oqibatlarga e'tibor bering. Xususiyat faqat ba'zi holatlarda qo'llanilishi mumkin, bu erda raqobatlashuvchi konstruktorni haddan tashqari yuklanganligi mavjud emas, bu funksiya shabloni uchun eng yaxshi haddan ortiq yukni topadi, ammo bundan ham muhimi, mutaxassislik. Derivat sinf shablonining barcha mumkin bo'lgan mutaxassisliklarini qidirishi va har birining taklif etadigan tuzuvchilari to'plamini aniqlashi kerak, keyin esa eng yaxshi konstruktorni haddan tashqari yuklab olish va mahfiy sinf shablonini hal qilish kerak bo'ladi.

Siz taqdim etgan muayyan misolga qaraganda, std :: pair uchun ixtisosliklar mavjud emas, shuning uchun oddiy holatdamiz va yuqoridagi misol kodi muvaffaqiyatsiz bo'ladi:

pair p = pair( 10, 20 );

Nima uchun? Xo'sh, bu aslida muammo, bu xususiyat foydalanuvchilarga bir oz chalkashlik keltiradi. Yuqorida aytib o'tganimdek, ifodani o'ng tomonida osonlik bilan ortiqcha yuklanganlik bilan echish mumkin (ixtisoslik yo'q deb faraz qilinadi) va bu argumentlarni int deb atash mumkin, ikkalasi ham . Shunday qilib, birinchi qadam ushbu ifodani quyidagicha ifodalaydi:

pair p = pair(10,20);

Now, that is equivalent to pair p( pair( 10, 20 ) ), and we need the second step of resolution, and at this point, the compiler will see that there is a templated constructor:

template 
struct pair {
   first_type first;
   second_type second;

   template 
   pair( U f, V s ) : first(f), second(s) {}
};

That means that every potential instantiation of std::pair has a perfect match for that constructor call, and the compiler cannot select, nor provide any sensible error message other than ambiguous in too many ways.

Now imagine coming to your favorite Q&A forum on the internet and guess how many questions would arise from this type of details. Ignoring the cost of implementing the feature, the result of having it in the language is that the language would be more complex and harder to write, it would impose an even steeper learning curve, and all that for basically no real value: in the cases where deduction can be applied, it is trivial to write a helper function that will provide the same advantages, like make_pair with no added cost.

Ushbu turlarni taqdim qilish kerakligi foydalanuvchi tomonidan murakkablikni keltirib chiqaradi: kompilyator men uchun to'g'ri turdagi dediktsin ga ega bo'ladimi, yo'qmi deb o'ylashning hojati yo'q. Ushbu ma'lumotlarga e'tibor bermaslik siz hal qilmoqchi bo'lgan muammoni hal qilish uchun sizga ko'proq vaqt ajratadi.

Ba'zan kam yaxshi dir.

BTW, auto buni eng ahamiyatsiz tarzda hal qiladi: unda mos keladigan konstruktorni topishga hojat yo'q, o'ng tarafdagi ifoda juda sodda: faqat bitta ob'ekt bilan ishlaydi va yangi turdagi ushbu turdagi foydalanadi. Keyinchalik, soddalashtirilgan foydalanish holatlarida, auto uchun chegirmalarni mos yozuvlar yaratish uchun ishlatilishi mumkinmi yoki yo'qmi, yoki yechim topilmaguncha, oldingi va keyingi tartibda muhokama qilindi. Const yoki uchuvchi chiqarilgan turdagi qismi bo'lishi mumkin ...

Faqat bitta fikr: derleyici ishlatmasdan, std :: min (10, 5.0) so'zining turi nimadan iborat?

2
qo'shib qo'ydi
Umumiy murakkablik nuqtasi bilan bahslashmasa-da, "muayyan konstruktor mavjudligini ko'rsangiz ... pair (U f, V s) " - konstruktorlar bir bitta </​​i> ( pair ) argumenti bilan mos kelmasligi std :: juftlik (juft &&)
qo'shib qo'ydi muallif Tony Delroy, manba
Yordamchi funktsiyalar yaratish yukini sinchkovlik bilan saqlash, shuningdek, nom maydoni ifloslanishini hisobga olmaysiz. Shablonni tahlil qiladigan kutubxonani yozish Men juda ko'p funktsiyani topdim va men yordamchi funktsiyalarni topdim, aslida men faqat yordamchilarga ega _function.h fayllarim bor. Nomlar atrof-muhit ifloslanishi ham yomon natijadir, chunki make_something ishlatish odatda noto'g'ri nomlashdir va deyarli har bir sinf yordamchi bilan birlashtirish kerak, vazifalar tegishli nomlarni oldi va to'qnashuvlar prefiks bilan o'zgartirilsin.
qo'shib qo'ydi muallif Gene Bushuyev, manba