Неявные преобразования С++
Несколько комментариев по моему недавнему ответу, Какие другие полезные приведения могут быть использованы в С++, свидетельствуют о том, что мое понимание конверсий на С++ ошибочно. Чтобы прояснить эту проблему, рассмотрите следующий код:
#include <string>
struct A {
A( const std::string & s ) {}
};
void func( const A & a ) {
}
int main() {
func( "one" ); // error
func( A("two") ); // ok
func( std::string("three") ); // ok
}
Мое утверждение состояло в том, что первый вызов функции является ошибкой, потому что нет никакого преобразования из const char * в A. Существует преобразование из строки в A, но использование этого будет включать в себя больше, чем один конвертация. Я понимаю, что это недопустимо, и это, похоже, подтверждается компиляторами g++ 4.4.0 и Comeau. С Comeau я получаю следующую ошибку:
"ComeauTest.c", line 11: error: no suitable constructor exists
to convert from "const char [4]" to "A"
func( "one" ); // error
Если вы можете указать, где я ошибаюсь, либо здесь, либо в исходном ответе, желательно со ссылкой на стандарт С++, сделайте это.
И ответ со стандартом С++ выглядит следующим образом:
Не более одного пользовательского преобразования (функция конструктора или преобразования) неявно применяется к одному значению.
Спасибо Абхай за предоставление цитаты.
Ответы
Ответ 1
Я думаю, что ответ от sharptooth является точным. Раздел 12.3.4 С++ Standard (SC22-N-4411.pdf) под названием "Конверсии" дает понять, что допускается только одно неявное пользовательское преобразование.
1 Тип преобразования объектов класса может быть задан конструкторы и конверсия функции. Эти конверсии называются пользовательскими преобразованиями и используются для неявных преобразований типов (пункт 4), для инициализация (8.5) и для явного преобразования типов (5.4, 5.2.9).
2 Пользовательские преобразования применяются только там, где они однозначно (10.2, 12.3.2). Конверсии подчиняются правила контроля доступа (пункт 11). Контроль доступа применяется после двусмысленность (3.4).
3 [Примечание: см. 13.3 для обсуждения использования конверсий в вызовах функций, а также в примерах ниже. -конец примечание]
4 Не более одного определяемого пользователем преобразования (конструктор или преобразование функция) неявно применяется к Один значение.
Ответ 2
Поскольку консенсус, похоже, уже есть: да, вы правы.
Но поскольку этот вопрос/ответы, вероятно, станет точкой отсчета для неявных преобразований С++ в stackoverflow, я бы хотел добавить, что для аргументов шаблона правила разные.
Не допускаются неявные преобразования для аргументов, которые используются для вычитания аргумента шаблона. Это может показаться довольно очевидным, но тем не менее может привести к тонкой странности.
Случай в точке, std::string операторы сложения
std::string s;
s += 67; // (1)
s = s + 67; // (2)
(1) компилируется и работает нормально, operator+=
является функцией-членом, шаблонный параметр шаблона уже выводится путем создания экземпляра std::string
для s (до char
). Таким образом, допускаются неявные преобразования (int
→ char
), приводит к s, содержащему эквивалент char, равный 67, например. в ASCII это станет "C"
(2) дает ошибку компилятора, поскольку operator+
объявляется как свободная функция, и здесь аргумент символа шаблона используется в выводе.
Ответ 3
Это правда, допускается только одно неявное преобразование.
Два преобразования в строке могут выполняться с комбинацией оператора преобразования и параметризованного конструктора, но это вызывает предупреждение C4927 - "незаконный преобразование, недвусмысленно применяется более одного пользовательского преобразования" - в VС++ по какой-либо причине.
Ответ 4
Язык программирования С++ (4-е изд.) (раздел 18.4.3) гласит, что
только один уровень пользовательских неявное преобразование является законным
Эта "определяемая пользователем" часть делает ее похожей на несколько неявных преобразований, если некоторые из них находятся между нативными типами.