Зачем использовать const для неявного преобразования?
-
29-09-2019 - |
Вопрос
После тщательного прочтения ISO/IEC 14882, Язык программирования – C++ Я все еще не уверен, почему const
необходим для неявного преобразования в пользовательский тип с помощью конструктора с одним аргументом, подобного следующему
#include <iostream>
class X {
public:
X( int value ) {
printf("constructor initialized with %i",value);
}
}
void implicit_conversion_func( const X& value ) {
//produces "constructor initialized with 99"
}
int main (int argc, char * const argv[]) {
implicit_conversion_func(99);
}
Начиная с раздела 4, строка 3
Выражение e может быть неявно преобразовано в тип T тогда и только тогда, когда объявление T t=e;является хорошо сформированной для некоторой изобретенной временной переменной t (8.5).Некоторые языковые конструкции требуют, чтобы выражение было преобразовано в логическое значение.Говорят, что выражение e, появляющееся в таком контексте, контекстуально преобразовано в bool и является корректно сформированным тогда и только тогда, когда объявление bool t(e);является хорошо сформированной для некоторой изобретенной временной переменной t (8.5).Эффект любого неявного преобразования такой же, как при выполнении объявления и инициализации, а затем использовании временной переменной в качестве результата преобразования.Результатом является значение lvalue, если T является ссылочным типом lvalue (8.3.2), и значение rvalue в противном случае.Выражение e используется в качестве lvalue тогда и только тогда, когда инициализация использует его в качестве lvalue.
После этого я нашел раздел об инициализаторах, связанных с пользовательскими типами, в строке 6 8.5
Если программа вызывает инициализацию по умолчанию объекта с постоянным типом T, T должен быть типом класса с предоставленным пользователем конструктором по умолчанию.
Наконец, я дошел до 12.3, строка 2 о пользовательских преобразованиях, в которой говорится
Пользовательские преобразования применяются только там, где они однозначны (10.2, 12.3.2).
Излишне говорить, что 10.2 и 12.3.2 не ответили на мой вопрос.
- Может ли кто-нибудь пролить некоторый свет на то, какой эффект
const
влияет на неявные преобразования? - Означает ли использование
const
сделать преобразование "однозначным" для строки 12.3 2? - Делает
const
как-то повлиять на значение по сравнениюзначение, о котором говорилось в разделе 4?
Решение
На самом деле это не имеет большого отношения к тому, что преобразование является неявный.Более того, на самом деле это не имеет особого отношения к преобразования.Речь действительно идет о значения rv против. значения.
Когда вы конвертируете 99
чтобы ввести X
, в результате получается значение rv.В C ++ результаты преобразований всегда являются rvalues (если только вы не преобразуете в ссылочный тип).В C ++ запрещено присоединять неконстантные ссылки к rvalues.
Например, этот код не будет компилироваться
X& r = X(99); // ERROR
потому что он пытается прикрепить неконстантную ссылку к rvalue.С другой стороны, этот код в порядке
const X& cr = X(99); // OK
потому что совершенно нормально присоединять ссылку const к rvalue.
То же самое происходит и в вашем коде.Тот факт, что это включает в себя неявное преобразование, как бы не относится к делу.Вы можете заменить неявное преобразование с явным один
implicit_conversion_func(X(99));
и в итоге оказываемся в той же ситуации:с const
он компилируется, без const
это не так.
Опять же, единственная роль, которую играет преобразование (явное или неявное) здесь, заключается в том, что оно помогает нам получить rvalue .В общем, вы можете создать rvalue каким-либо другим способом и столкнуться с той же проблемой
int &ir = 3 + 2; // ERROR
const int &cir = 3 + 2; // OK
Другие советы
В соответствии с разделом 5.2.2 пункт 5, когда аргумент на функцию имеет const
Справочный тип, временная переменная автоматически вводится при необходимости. В вашем примере результат RVALUE X(99)
должен быть введен во временную переменную, чтобы эта переменная была передана const
ссылка на implicit_conversion_func
.