Больше не лучше вообще. Когда вам нужно спроектировать систему, вы должны быть осторожны с тем, как взаимодействуют различные функции, и должны выбрать самое простое и простое решение, которое предоставляет больше всего пользователям. Типичные вопросы начинаются с: что будет предлагать функция пользователям , какая стоимость потребует функция и , какие проблемы может принести функция .
В этом случае предоставление вывода типа помогает в том, что вы можете пропустить предоставление типа при объявлении переменной или при непосредственном вызове конструктора:
pair p = pair( 10, 20 );
Объявление переменной можно сделать с помощью auto
, так что это больше не проблема, но это могло быть мотивирующей причиной для этой функции. В случае вызова конструктора добавленное значение весьма ограничено, вы можете предоставить именованный конструктор , как в стандартной библиотеке:
auto p = make_pair( 10, 20 );
Итак, в конце концов, добавленная стоимость возможности прямого вызова конструктора фактически ограничена, так как вы всегда можете предоставить именованную функцию, которая создаст объект для вас. Обратите внимание, что потенциальные дополнительные копии оптимизируются, что означает, что при вызове make_pair
не требуется никаких дополнительных затрат по сравнению с прямым вызовом пары конструктора (10,20)
Теперь сосредоточимся на негативных последствиях, которые эта функция может иметь в пользовательском коде. Эта функция может быть использована только в некоторых случаях, когда нет конкурирующих перегрузок конструктора, так же, как она находит наилучшую перегрузку для шаблона функции, но, что более важно, специализации. Компилятор должен будет найти все потенциальные специализации шаблона класса и определить набор конструкторов, который предлагает каждый из них, а затем он должен будет разрешить наилучшую перегрузку конструктора и шаблон класса, в который он включен.
Оглядываясь назад на конкретный пример, который вы предоставили, для std::pair
нет специализаций, поэтому мы находимся в простом случае, и все же приведенный выше пример кода потерпит неудачу:
pair p = pair( 10, 20 );
Почему? Ну, это на самом деле проблема, эта функция может привести пользователей в замешательство. Как я уже упоминал, правая часть выражения может быть легко разрешена с простым разрешением перегрузки (при условии, что специализаций не существует), и это вывело бы аргументы int
, оба из них. Таким образом, первый шаг выведет выражение:
pair p = pair<int,int>(10,20);
Теперь это эквивалентно pair p( pair<int,int>( 10, 20 ) )
, и нам нужен второй шаг разрешения, и на этом этапе компилятор увидит, что существует шаблонный конструктор:
template <typename first_type, typename second_type>
struct pair {
first_type first;
second_type second;
template <typename U, typename V>
pair( U f, V s ) : first(f), second(s) {}
};
Это означает, что каждое потенциальное создание экземпляра std::pair<T,U>
имеет идеальное соответствие для этого вызова конструктора, и компилятор не может ни выбрать, ни предоставить какое-либо разумное сообщение об ошибке, кроме , неоднозначно слишком много способов .
А теперь представьте, что вы заходите на ваш любимый форум вопросов и ответов в Интернете, и догадайтесь, сколько вопросов возникнет из-за такого рода деталей. Игнорирование стоимости реализации этой функции приводит к тому, что язык будет более сложным и трудным для написания, что приведет к еще более крутой кривой обучения, и все это, по сути, не имеет реальной ценности: в случаях там, где может применяться вычет, написать тривиальную функцию, которая обеспечит те же преимущества, что и make_pair
, без дополнительных затрат , тривиально.
Тот факт, что вы должны предоставить типы, снимает сложность у пользователя: нет необходимости думать, сможет ли компилятор определить правильный тип для меня. Отсутствие необходимости сосредотачиваться на этих деталях дает вам больше времени, чтобы подумать о реальной проблеме, которую вы хотите решить.
Иногда меньше - это лучше .
Кстати, auto
решает это самым тривиальным способом: ему не нужно находить конструктор , который будет сопоставлять и угадывать тип из него, а просто использовать тип правой руки выражение-стороны, которое намного проще: работает только с одним объектом и использует этот тип для нового объекта. И даже тогда, с очень упрощенным вариантом использования, он обсуждался взад и вперед до тех пор, пока не было согласовано решение, с деталями, являющимися тем, можно ли использовать вычет для auto
для создания ссылок или const
или volatile
будет частью выведенного типа ...
Просто мысль: без использования компилятора, какой тип выражения std::min( 10, 5.0 )
?