Почему параметры типа шаблона не выводятся как «константные»?

Возможный дубликат:
вывод ссылок на const из Аргументы rvalue

Если у меня есть

template<class T>
void foo(T &) { }

и я называю это как foo((const int)5), учитывая, что аргумент является const int, почему компилятор автоматически не выводит T как const int?


person user541686    schedule 13.08.2012    source источник


Ответы (2)


Да, если ему задан константный тип. Однако значения R (значения prvalue в C++11) с типами, не относящимися к классу, никогда не являются cv-квалифицированными, даже если вы пытаетесь сказать, что это так: выражение ((const int)5) имеет тип int. Причина здесь в том, что cv-квалификации применяются только к объектам, а временные объекты неклассовых типов являются не объектами, а чистыми значениями; cv-квалификация не может применяться, потому что нет ничего, что могло бы быть const или volatile.

Если вы пишете:

int const i = 42;
foo( i );

, ваш шаблон будет создан с T = int const. (Как вы написали, код не должен компилироваться, потому что выведенный тип — int, поэтому функция принимает int&, который не может быть инициализирован значением r.)

person James Kanze    schedule 13.08.2012
comment
Просто чтобы уточнить, о каком именно неклассовом типе вы говорите? int или int& или const int или const int&? (Я не уверен, что знаю значение этого термина достаточно хорошо, чтобы понять ваш ответ.) - person user541686; 13.08.2012
comment
Поскольку мы говорим о добавлении к нему cv-квалификаторов, тип должен быть int. По крайней мере, в исходном коде тип был бы int const (после приведения), за исключением того, что rvalue неклассового типа не имеет модификаторов cv. (Интересно отметить, что приведение к int const& должно работать.) - person James Kanze; 13.08.2012
comment
Ого, так struct Foo { }; foo((const Foo)Foo()); работает нормально?! Я никогда этого не знал! +1 абсолютно бессмысленно, почему int отличается от произвольного struct, но это кажется правильным объяснением, спасибо .. - person user541686; 13.08.2012
comment
@Мехрдад История. Это не имеет смысла, за исключением того, что в C rvalue никогда не уточняется cv, а C++ хочет вести себя идентично (хотя в данном случае я не вижу, какое это может иметь значение). Но то, является ли тип класса константным или нет, влияет на разрешение перегрузки функции: например, какую функцию вы вызываете в чем-то вроде foo().bar(). Таким образом, квалификаторы cv должны влиять на типы классов. Во всяком случае, это обоснование, которое мне дали. - person James Kanze; 13.08.2012
comment
В чем именно будет разница между обычным 42 и константным 42? - person fredoverflow; 14.08.2012
comment
@FredOverflow Тип, поскольку const является частью системы типов C++. (Предположительно, если бы C++ пошел по этому пути, тип 42 был бы int const, и не было бы литерала с типом только int.) - person James Kanze; 14.08.2012

Тип целочисленного литерала — int, а не const int, согласно стандарту C++03, пункт 2.12.1.2.

Тип целочисленного литерала зависит от его формы, значения и суффикса. Если он десятичный и не имеет суффикса, он имеет первый из этих типов, в которых может быть представлено его значение: int, long int;...

Обновить

Другим релевантным правилом вывода типа может быть 14.8.2.1.2.

Если P не является ссылочным типом:

[...]

— Если A является cv-квалифицированным типом, cv-qualifiers верхнего уровня типа A игнорируются для вывода типа.

Если P является cv-квалифицированным типом, cv-квалификаторы верхнего уровня типа P игнорируются для вывода типа.

Если P является ссылочным типом, тип, на который ссылается P, используется для вывода типа.

Код, предоставленный OP, даже не будет компилироваться, потому что незаконно привязывать неконстантную ссылку к rvalue.

person Andrey    schedule 13.08.2012
comment
Ого, правда? Я этого не знал, спасибо, что сообщили мне ... Думаю, у меня был плохой пример в вопросе для иллюстрации моей точки зрения. Я просто исправил это в вопросе. Но проблема все еще сохраняется, даже когда я явно привожу ее к const int, так что это не настоящая проблема, верно? - person user541686; 13.08.2012
comment
@Mehrdad, какая именно проблема? - person SingerOfTheFall; 13.08.2012
comment
@SingerOfTheFall: это в названии. Когда я передаю параметр const в foo, например, в моем (фиксированном) примере, почему T не выводится как заданный тип const? - person user541686; 13.08.2012
comment
@Mehrdad: Если вы действительно передали аргумент const lvalue, например const int i = 42; foo(42); , он будет. Проблема не в const-ности, а в lvalue-/rvalueness. - person Xeo; 13.08.2012
comment
@Xeo: Э-э, тогда почему это не работает с r-значениями? - person user541686; 13.08.2012
comment
@Mehrdad - с чего ты взял, что это не const? - person Kiril Kirov; 13.08.2012
comment
@KirilKirov: Потому что он даже не компилируется (см. мой пример). - person user541686; 13.08.2012
comment
@Mehrdad: Потому что так говорят правила. int& также не связывается с rvalue типа int, так почему же T& должно связываться с rvalue типа T? Это как раз тот тип дедукции аргумента игрового шаблона, который играет. - person Xeo; 13.08.2012
comment
@Xeo: почему T& должно привязываться к rvalue типа T?... подождите, но T еще даже не существует, поэтому возникает вопрос, почему T& должно связываться с T даже не имеет смысла, поскольку предполагает, что T существует как реальный тип. T должно быть сначала выведено, поэтому я спрашиваю, почему оно не выводится как const int? Если бы это было выведено как const int, тогда const int& вполне могло бы связать с const int, без проблем. - person user541686; 13.08.2012
comment
Андрей: Спасибо за ссылку на стандарт. Вы случайно не знаете, почему стандарт явно игнорирует модификатор A const при выводе типа? (Это предназначено для защиты от какой-то ошибки, или компилятору требуется слишком много времени, чтобы выяснить это, или что-то еще?) Я предполагаю, что решение не было принято произвольно, учитывая, что оно упоминается явно, хотя оно предотвращает компиляцию кажущегося корректным кода. - person user541686; 13.08.2012
comment
Ваши комментарии хороши, но они не применимы к его примеру. Он создает экземпляр не целочисленным литералом, а выражением приведения. И применяется только последний пункт вашей второй цитаты, поскольку в его случае P является ссылочным типом (без константы верхнего уровня). Причина, по которой его код не компилируется (или приводит к T = int в одном неисправном компиляторе), заключается в том, что выражение ((int const)5) является rvalue неклассового типа, а rvalue неклассового типа не имеют cv-квалификаторов (даже если вы прямо говорите, что они должны). - person James Kanze; 13.08.2012
comment
@Mehrdad: Джеймс Канце только что дал отличное объяснение. Соответствующий пункт стандарта — 3.10/9: non-class rvalues always have cv-unqualified types - person Andrey; 13.08.2012
comment
@Andrey: Да, я видел его ответ, спасибо. :) - person user541686; 13.08.2012