Чаму не аргументы класа шаблону канструктара вызначаецца аўтаматычна?

Разгледзім наступны клас:

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

Далей не дапускаецца ў C ++:

auto p = Pair(10, 10);

Чаму гэта не дазволена? тыпы могуць быць цалкам вызначаны пры выкліку канструктара.
Я ведаю, што ёсць абыходны шлях для гэтага, як:

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

Але чаму гэта неабходна? Чаму не кампілятар проста вызначыць тып з аргументаў гэтак жа, як гэта робіць з шаблону функцыі? Можна сказаць, што яго таму, што стандарт не дазваляе, так чаму не стандарт дазваляе гэта?

Edit:
Для тых, хто кажа, што гэта прыклад, чаму гэта не павінна быць дазволена:

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

Я магу зрабіць менавіта гэта з шаблонамі функцый перагрузкі:

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

Чаму гэта дазволена для функцый, але не для класаў?

13
@GeneBushuyev: Вы паказваеце, што вы хочаце, канструктар па «выклікаюць» класа.
дададзена аўтар Dani, крыніца
Два MakePair рэалізацыя ў канцы неадназначная, вы можаце напісаць іх, але Вам трэба будзе падаць тыпы шаблону функцыі, так як кампілятар не можа падабраць найлепшыя перагрузкі.
дададзена аўтар David Rodríguez - dribeas, крыніца
<�Код> Я не магу зрабіць менавіта гэта з шаблонамі функцый перагрузкай: На самай справе, няма, вы не можаце, па тых жа прычынах. Гэта неадназначнае. codepad.org/axjCAZyL
дададзена аўтар Mooing Duck, крыніца
@Mooing: Я думаю, што ён кажа, што ён можа стварыць тую ж няяснасць з функцыяй перагрузкай, якія існуюць з канструктарам перагрузкай, у гэтым выпадку, вам трэба паказаць аргументы шаблону.
дададзена аўтар Benjamin Lindley, крыніца
таму што канструктары не маюць імёнаў, і гэта немагчыма назваць іх, выснова аргументу працуе толькі для выклікаў функцый.
дададзена аўтар Gene Bushuyev, крыніца

3 адказы

Гэта тое, што Бьерн Страуструп павінен сказаць па гэтым пытанні:

<�Р> Звярніце ўвагу, што аргументы шаблону класа ніколі не выводзяцца. Прычына ў тым,   што гнуткасць забяспечваецца некалькі канструктараў для класа   зраблю такі вылік немагчыма ў многіх выпадках і невыразны шмат у чым   больш.
10
дададзена
Тое ж самае можна сказаць і пра функцыі шаблону перагрузцы
дададзена аўтар Dani, крыніца
Дададзены прыклад у рэдагаванні
дададзена аўтар Dani, крыніца
Розніца ў тым, што няма ніякай двухсэнсоўнасці тыпу ствараецца з дапамогай перагрузкі шаблону функцыі, таму што тыпу не ствараюцца. Вышэй не вельмі добра сфармуляваныя, але я спадзяюся, што вы мяне разумееце?
дададзена аўтар John Dibling, крыніца
Доўгі час таму, калі аўто ўпершыню быў уведзены, я прапанаваў выкарыстаць гэты сінтаксіс для ctors аргументу дэдукцыі, напрыклад, <�Код> пара <�аўто, аўто> (10,10) . Гэта можа быць змяшаны з выкарыстаннем псеўданіма дэкларацыю: выкарыстоўваючы mypair = пара <�аўто, аўто> таму можна напісаць mypair р (10,10); замест аўтаматычны р = make_pair (10,10); . Гэты сінтаксіс зрабіў бы дапаможныя функцыі make_something() (які не служыць ніякай іншай мэты, акрамя тыпу дэдукцыі) непатрэбная.
дададзена аўтар Gene Bushuyev, крыніца

Разгледзім наступнае.

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
дададзена
@David: але ў выпадку, калі ён не з'яўляецца неадназначным, чаму яно не дазволена? Вы сказалі, што яго таму, што гэта можа быць неадназначным, так што я прывёў прыклад функцый, якія могуць быць неадназначныя таксама, але гэта дазволена ў функцыі ў агульным выпадку, але не ў класах, у агульным выпадку.
дададзена аўтар Dani, крыніца
Дададзены прыклад у рэдагаванні
дададзена аўтар Dani, крыніца
Тое ж самае можна зрабіць з дапамогай шаблону функцыі перагрузкі.
дададзена аўтар Dani, крыніца
@Benjamin: Таму што гэта не unambigious.
дададзена аўтар John Dibling, крыніца
@Dani, у агульных рысах, выдаляецца, так як значэнне яны дадаюць не кампенсуе дадатковую складанасць у альбо праграмах кампілятара або карыстальніка. Вы ведаеце (без выкарыстання кампілятара), што тып станд :: мін (10, 5.0) гэта?
дададзена аўтар David Rodríguez - dribeas, крыніца
@Dani: Дададзены прыклад (два MakePair ) з'яўляецца неадназначным. У той час як вы можаце пісаць, вы не можаце назваць іх без ўручную паказаць тыпы, і што ў сваю чаргу азначае, што вы вярнуліся на першым этапе: таго, каб зрабіць тыпы відавочным.
дададзена аўтар David Rodríguez - dribeas, крыніца
@BenjaminLindley: увесь код на гэтай старонцы дагэтуль, пара <�ИНТ, двайны>() адпавядае дзве розныя функцыі. У тыпу ня неадназначныя, то функцыі ёсць.
дададзена аўтар Mooing Duck, крыніца
Er, упс. <�Код> пары (10, 10,0) адпавядае як Пара :: Пара (Const T1 & Па-першае, Const T2 & Second) і Пара :: Pair (Const T2 & Па-другое, канстантнасцю T1 & Першы) . <�Код> MakePair (10,10.0) адпавядае і MakePair (Const T1 & Па-першае, Const Т2 і другі) і MakePair (Const Т2 & Па-другое, Const T1 & Першы) , так што ва ўсіх выпадках, званкі неадназначныя.
дададзена аўтар Mooing Duck, крыніца
О, у арыгінальным класе OP, няма ніякай двухсэнсоўнасці. Я не магу думаць пра прычыну, што распрацоўшчыкі мовы забараняў гэта. цытата Бьерн Страуструп зьяўляецца ня шмат прычын на самай справе.
дададзена аўтар Mooing Duck, крыніца
@Dani: Я бачу вашу кропку. Чаму ён не можа выводзіць тыпы ў тых выпадках, калі гэта адназначна, правільна? Я буду думаць пра гэта.
дададзена аўтар Benjamin Lindley, крыніца
@John: Калі няма ніякіх перагрузак, як адзін у класе я паказаў, і ні спецыялізацый, як гэта неадназначна?
дададзена аўтар Benjamin Lindley, крыніца
IOW, што яшчэ можа Пара (10,10.0) азначае, акрамя пара <�ИНТ, двайны> (10,10.0) ?
дададзена аўтар Benjamin Lindley, крыніца
@Mooing Duck: Я не пайду за табой. Ва ўсіх код на гэтай старонцы дагэтуль, пара <�ИНТ, двайны>() не супадае ні з чым, як ні мой клас, ні Дані мае канструктар па змаўчанні.
дададзена аўтар Benjamin Lindley, крыніца
@Mooing: Але я маю на ўвазе арыгінальны клас Ор, дзе няма Пара :: Пара (Const T2 і другое, Const T1 & First) , а дзе двухсэнсоўнасць там?
дададзена аўтар Benjamin Lindley, крыніца
@Dani: Як менавіта?
дададзена аўтар Benjamin Lindley, крыніца

Больш не лепш наогул. Калі вы павінны распрацаваць сістэму, вы павінны быць асцярожныя з тым, як узаемадзейнічаюць паміж сабой рознымі функцыямі, і павінны выбраць найчыстае простае рашэнне, якое забяспечвае найбольш карыстальнік. Тыповыя пытанні пачынаюцца з , што будзе функцыя прапанаваць карыстальнікам , што кошт будзе функцыя патрабуе і , якія праблемы могуць прывесці функцыя .

У гэтым выпадку, пры ўмове тыпу вылік дапамагае ў тым, што вы можаце прапусціць прадастаўленне тыпу пры аб'яўленні зменнай ці пры выкліку канструктара наўпрост:

pair p = pair( 10, 20 );

Аб'яву зменнай можа быць зроблена з аўто , так што гэта ўжо не праблема, але яна магла б быць матывіровачную прычына для гэтай функцыі. У выпадку выкліку канструктара на даданую вартасць з'яўляецца вельмі абмежаваным, вы можаце прадаставіць з імем канструктара , так як ёсць у стандартнай бібліятэцы:

auto p = make_pair( 10, 20 );

Такім чынам, у рэшце рэшт, дададзены кошт на магчымасць выклікаць канструктар непасрэдна на самай справе абмежаваная, так як вы заўсёды можаце прадаставіць указаную функцыю, якая будзе ствараць аб'ект для вас. Звярніце ўвагу, што патэнцыйныя дадатковыя копіі аптымізаваныя ў бок, што азначае, што няма ніякіх дадатковых выдаткаў у закліку make_pair супраць прамога выкліку канструктара `пары (10,20)

Цяпер, засяродзіць увагу на негатыўныя наступствы, што функцыя можа мець у карыстацкім кодзе. Гэтая функцыя будзе выкарыстоўвацца толькі ў некаторых выпадках, калі няма ні аднаго канкуруючых канструктару перагрузак, такім жа чынам, што ён знаходзіць лепшую перагрузку для шаблону функцыі, але яшчэ важней спецыялізацыі. Кампілятар будзе мець для пошуку ўсіх магчымых спецыялізацый шаблону класа, і вызначае набор канструктараў, якія кожны з іх прапаноўваюць, а затым ён павінен вырашыць лепшыя перагрузкі канструктара і шаблон класа ўшыты.

Азіраючыся на канкрэтным прыкладзе, які вы паказалі, няма спецыялізацыі для станд :: пары , таму мы ў простым выпадку, і яшчэ прыклад кода вышэй, будзе трываць няўдачу:

pair p = pair( 10, 20 );

Чаму? Ну, гэта на самай справе праблема, гэтая функцыя будзе прынесці нямала блытаніны для карыстальнікаў. Як я ўжо казаў, правы бок выразы можа быць лёгка вырашаная з простай дазволу перагрузкі (пры ўмове, што няма спецыялiзацыi), і было б вывесці аргументы, каб быць Int , абодва з іх , Такім чынам, першы крок будзе вывесці выраз:

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.

Той факт, што вы павінны даць тыпы адымае складанасці ад гэтага карыстальніка: няма неабходнасці думаць аб Ці кампілятар зможа </Выведзіце EM> правільны тыпу для мяне. Не маючы, каб засяродзіцца на гэтых дэталях сыходзіць больш часу, каб думаць аб рэальнай праблеме, якую вы хочаце вырашыць.

Часам менш з'яўляецца лепш .

Дарэчы, аўто дазваляе гэта самым трывіяльным чынам: гэта не трэба, каб знайсці канструктар , які будзе адпавядаць і адгадаць тып ад яго, а проста выкарыстоўваць тып правая бок выразы, якое значна прасцей: працуе толькі з адным аб'ектам, і выкарыстоўвае гэты тып для новага аб'екта. І нават тады, з вельмі спрошчаным прэцэдэнтам, яно абмяркоўвалася назад і наперад да таго часу, пакуль раствор не быў узгоднены з дэталлю, ці з'яўляецца вылік аўто можа быць выкарыстана для стварэння спасылак, або <�кода > Const або лятучы будзе часткай выведзенага тыпу ...

Проста думка: без выкарыстання кампілятара, што тып выказвання станд :: мін (10, 5,0) ?

2
дададзена
Ня спрачаючыся з агульнай кропкай складанасці, але зноў канкрэтнае пытанне «бачыць, што ёсць шаблонны канструктар ... пары (U F, V s) » - канструктары звалі з <�я> адзіночны ( пара ) аргумент таму не ўзгадненне адназначна было б лепш за ўсё з станд :: пары (пара &&) (8) у cppreference ?
дададзена аўтар Tony Delroy, крыніца
Вы недаацэньваеце цяжар стварэння дапаможных функцый, захоўваючы іх у сінхранізацыі, а таксама прастора імёнаў забруджвання. Напісанне бібліятэкі шаблонаў парсера я знайшоў вялікую колькасць функцый гэтых дапаможных функцый, на самай справе ў мяне ёсць шмат <�што-небудзь> _function.h файлы толькі з памочнікамі. Забруджванне прастор імёнаў таксама непрыемны вынік гэтага, таму што з дапамогай кнопак make_something , як правіла, дрэнна найменне, і практычна кожны клас павінен быць створаны з дапамогай памочніка, функцыі ўзялі адпаведныя імёны і тыпы, каб пазбегнуць сутыкнення было быць зменены з прэфіксам.
дададзена аўтар Gene Bushuyev, крыніца