Здравствуйте, Eugene Sh, Вы писали:
ES>Первый вариант выглядит лучше. А с точки зрения быстродействия разницы нет — в обоих случаях вызовется конструктор копирования.
Prefer using the form "T t(u);" instead of "T t = u;" where possible. The former usually works wherever the latter works, and has other advantages—for example, it can take multiple parameters.
Здравствуйте, igna, Вы писали:
ES>>Первый вариант выглядит лучше. А с точки зрения быстродействия разницы нет — в обоих случаях вызовется конструктор копирования.
I>
I>Prefer using the form "T t(u);" instead of "T t = u;" where possible. The former usually works wherever the latter works, and has other advantages—for example, it can take multiple parameters.
I>Ты с этим не согласен или считаешь инициализацию std::complex особым случаем? Почему?
Я, к примеру, не имею ничего против записи "T t(u);", но вариант с "=" лично мне более привычен. А упомянутое преимущество "может принимать несколько параметров" ИМХО несколько надумано — никто не мешает записать "T t = T(u1, u2)" Понятно, что разница между инициализацией копированием и прямой инициализацией есть, но в абсолютном большинстве случаев это совершенно несущественно.
Здравствуйте, Bell, Вы писали:
B>Я, к примеру, не имею ничего против записи "T t(u);", но вариант с "=" лично мне более привычен.
Это относится и к std::complex? И к boost::shared_ptr? И к std::string? В том числе к std::string::string(const char*)? Может ты вообще всегда по-возможности используешь 'вариант с "="'?
Здравствуйте, igna, Вы писали:
B>>Я, к примеру, не имею ничего против записи "T t(u);", но вариант с "=" лично мне более привычен.
I>Это относится и к std::complex? И к boost::shared_ptr? И к std::string? В том числе к std::string::string(const char*)? Может ты вообще всегда по-возможности используешь 'вариант с "="'?
Если у меня не возникает ощущения дискомфорта, то я использую вариант с "=".
При работе с shared_ptr, например, использую вариант со скобочками, со строками — тоже. Класс complex использовать не приходилось, но первое ощущение — использовал бы вариант с "=".
В общем для меня это в большей степени субъективный выбор.
Ну а если есть подозрения на проблемы с эффективностью — так на это есть профайлер.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Bell, Вы писали:
B>>Я, к примеру, не имею ничего против записи "T t(u);", но вариант с "=" лично мне более привычен.
I>Это относится и к std::complex? И к boost::shared_ptr? И к std::string? В том числе к std::string::string(const char*)? Может ты вообще всегда по-возможности используешь 'вариант с "="'?
Здравствуйте, Bell, Вы писали:
B>Если у меня не возникает ощущения дискомфорта, то я использую вариант с "=". B>При работе с shared_ptr, например, использую вариант со скобочками, со строками — тоже. Класс complex использовать не приходилось, но первое ощущение — использовал бы вариант с "=". B>В общем для меня это в большей степени субъективный выбор.
Твое счастье. Я формалист, мне хотелось бы алгоритм выбора формализовать. Судя по книгам самого Саттера, давшего рекомендацию использовать "T t(u);", он сам не придерживается своей рекомендации буквально, мог бы и рекомендацию эту самую поточнее сформулировать, встроенные типы там исключить, может что-нибудь еще.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Bell, Вы писали:
B>>Я, к примеру, не имею ничего против записи "T t(u);", но вариант с "=" лично мне более привычен.
I>Это относится и к std::complex? И к boost::shared_ptr? И к std::string? В том числе к std::string::string(const char*)? Может ты вообще всегда по-возможности используешь 'вариант с "="'?
У shared_ptr я писал = везде, где можно, и часть кода сломалось, когда конструктор, принимающий auto_ptr внезапно стал explicit в 1.39.
С другой стороны, теперь конструирование shared_ptr через = можно использовать, чтобы подчеркнуть именно общее владение, а не передачу владения.
Здравствуйте, igna, Вы писали:
B>>Если у меня не возникает ощущения дискомфорта, то я использую вариант с "=". B>>При работе с shared_ptr, например, использую вариант со скобочками, со строками — тоже. Класс complex использовать не приходилось, но первое ощущение — использовал бы вариант с "=". B>>В общем для меня это в большей степени субъективный выбор.
I>Твое счастье.
Фууух, пронесло
I>Я формалист, мне хотелось бы алгоритм выбора формализовать. Судя по книгам самого Саттера, давшего рекомендацию использовать "T t(u);", он сам не придерживается своей рекомендации буквально, мог бы и рекомендацию эту самую поточнее сформулировать, встроенные типы там исключить, может что-нибудь еще.
Ну, может быть что-то вроде этого: если Вы боитесь создания лишнего временного объекта — используйте вариант со скобками.
Здравствуйте, Bell, Вы писали:
B>Ну, может быть что-то вроде этого: если Вы боитесь создания лишнего временного объекта — используйте вариант со скобками.
Может. А может еще проще, "используйте вариант со скобками" и все. Например:
int sum(int const a[], std::size_t const a_length)
{
int sum(0);
int const* const a_end(a + a_length);
for (int const* p(a); p < a_end; ++p)
sum += *p;
return sum;
}
Всюду, где возможно, я предпочитаю запись вида T x = y; — т.е. copy-initialization. Тем самым показывается использование неявного преобразования y к T, а значит, и родство между x и y — а именно: сущность y может быть использована там, где ожидается сущность типа T.
Здравствуйте, Николай Ивченков, Вы писали:
НИ>Всюду, где возможно, я предпочитаю запись вида T x = y; — т.е. copy-initialization. Тем самым показывается использование неявного преобразования y к T, а значит, и родство между x и y — а именно: сущность y может быть использована там, где ожидается сущность типа T.
С мнением Саттера ты конечно знаком:
Prefer using the form "T t(u);" instead of "T t = u;" where possible. The former usually works wherever the latter works, and has other advantages—for example, it can take multiple parameters.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, blackhearted, Вы писали:
B>>Со std::string самое интересное различие выходит
I>С std::string::string(const string&) или с std::string::string(const char*)?
Я с этим его мнением не согласен. Кстати, у Саттера допущена грубая неточность.
If u is of some other type, then this has the meaning "T t( T(u) );"—that is, u is first converted to a temporary T object, and then t is copy-constructed from that.
В direct-initialization кандидатами являются все конструкторы, а не только copy constructor. Причём в инициализации, где cv-unqualified тип инициализирующего выражения совпадает с cv-unqualified типом инициализируемого объекта, при разрешении перегрузки предпочтение может быть отдано некопирующему конструктору:
Здесь копирующий конструктор попросту не является viable function, и выбор падает на X(X const *). Что будет, если теперь заменить
X x(X(0));
на
X x = 0;
? Из стандарта следует, что эффект должен быть такой же. VC++ 8.0 с /Za, GNU C++ 4.1.2 и Comeau online нарушают требования стандарта, причём каждый по-своему. Все три компилятора выдают ошибку при попытке скомпилировать вышеуказанный пример с заменой на copy-initialization, и, кроме того,
VC++ с /Za выдаёт ошибку при попытке скомпилировать
struct X;
struct A
{
operator X const &() const;
};
struct X
{
X(X &);
template <class T>
X(T const &);
};
int f(X);
int main()
{
sizeof f(A());
}
— видимо, в direct-initialization, являющейся частью copy-initialization, он считает допустимыми кандидатами только копирующие конструкторы;
GNU C++ выдаёт ошибку при попытке скомпилировать
struct X;
struct A
{
operator X &() const;
};
struct X
{
X(X &);
private:
template <class T>
X(T const &);
};
int f(X);
int main()
{
sizeof f(A());
}
— это вообще странный глюк.
P.S. Ну, и если совсем уж придираться к тому, что написано у Саттера, то можно заметить, что T t( T(u) ); может быть объявлением функции в рамках его соглашений об u.
НИ>Из стандарта следует, что эффект должен быть такой же.
Отмечу, что здесь учитывается тот факт, что конструктор X(X const *) — неявный. В общем же случае можно получить разные результаты в полном соответствии со стандартом:
#include <iostream>
struct X
{
explicit X(int)
{ std::cout << "X(int)" << std::endl; }
X(long)
{ std::cout << "X(long)" << std::endl; }
};
int main()
{
X x1 = 0;
X x2(X(0));
}
Здравствуйте, Николай Ивченков, Вы писали:
НИ>P.S. Ну, и если совсем уж придираться к тому, что написано у Саттера, то можно заметить, что T t( T(u) ); может быть объявлением функции в рамках его соглашений об u.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Николай Ивченков, Вы писали:
НИ>>P.S. Ну, и если совсем уж придираться к тому, что написано у Саттера, то можно заметить, что T t( T(u) ); может быть объявлением функции в рамках его соглашений об u.
I>Это как?
Например так:
typedef int T;
typedef int u;
T t(T(u));
T (*pointer_to_function)(T f(u)) = &t;
--
Справедливость выше закона. А человечность выше справедливости.
igna:
НИ>>P.S. Ну, и если совсем уж придираться к тому, что написано у Саттера, то можно заметить, что T t( T(u) ); может быть объявлением функции в рамках его соглашений об u.
I>Это как?
Например, так:
#include <iostream>
typedef int T;
bool u;
int main()
{
T t( T(u) ); // эквивалентно T t(T u); или просто T t(T);
std::cout << sizeof t(0) << std::endl;
}
Здравствуйте, igna, Вы писали:
I>Здравствуйте, wander, Вы писали:
W>>В условии увидел только нули, отсюда и вариант W>>А вообще первый вариант, да.
I>Но если инициализация нулем, то все же int i = int();?
Вообще конечно зависит от ситуации. Я бы запись T i = T() применил бы в обобщенных функциях для инициализации значением по умолчанию. В случае int это будет ноль. В целом я больше склоняюсь к записи с '=' везде, где это целесообразно, лично для меня читаемость такого кода:
std::string str = "string";
намного выше, чем:
std::string str("string");
Как тут уже говорили, первая запись подчеркивает родство сущностей.
ЗЫ. А можно ответный вопрос. Это что, у тебя там спор какой-то с кем-то по этому поводу? Как-то не смахивает это на глобальную проблему человечества...
Здравствуйте, igna, Вы писали:
I>Это относится и к std::complex? И к boost::shared_ptr? И к std::string? В том числе к std::string::string(const char*)? Может ты вообще всегда по-возможности используешь 'вариант с "="'?
Я придерживаюсь простого формального правила: объекты с семантикой значения инициализирую через =, а объекты такой семантики лишённые через ()...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Bell, Вы писали:
B>Ну, может быть что-то вроде этого: если Вы боитесь создания лишнего временного объекта — используйте вариант со скобками.
Зачем этого бояться? Сначала нужно найти компилятор, который таки создаёт такой временный объект
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Я придерживаюсь простого формального правила: объекты с семантикой значения инициализирую через =, а объекты такой семантики лишённые через ()...
Еще одно мнение и опять не совпадающее с мнением Саттера. Странно, что в одной из must read книг по C++ дается совет, с которым похоже мало кто согласен, но признание в несогласии приходится вытягивать клещами.
Здравствуйте, wander, Вы писали:
W>ЗЫ. А можно ответный вопрос. Это что, у тебя там спор какой-то с кем-то по этому поводу?
Нет.
А можно все же ответ на мой вопрос? В необобщенном случае ты действительно напишешь int i = int();, вместо int i = 0;? Если нет, к чему был твой первый ответ?
Здравствуйте, Erop, Вы писали:
E>Я придерживаюсь простого формального правила: объекты с семантикой значения инициализирую через =, а объекты такой семантики лишённые через ()...
Согласно этому правилу std:auto_ptr и boost::shared_ptr нужно инициализировать по разному. Я правильно понял?
Здравствуйте, igna, Вы писали:
I>Согласно этому правилу std:auto_ptr и boost::shared_ptr нужно инициализировать по разному. Я правильно понял?
Да, и это хорошо, так как подчёркивает отсутствие семантики значения у std:auto_ptr...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, fay, Вы писали:
fay>Предпочитаю первый... Такая ошибка может обернуть веселыми минутами...
fay>int i(10);
fay>int i[10];
Честно говоря не вижу проблемы. Наверное можно сконструировать какой-нибудь (скорее искуственный) пример, но в большинстве случаев компилятор выдаст сообщение об ошибке когда попытаешься использовать целое вместо массива целых или наоборот.
Здравствуйте, igna, Вы писали:
I>Угу, а формальное определение семантики значения у тебя есть?
Копируемый, присваеваемый объект, который представляет сам себя и все копии которого эквивалентны.
А зачем это всё тебе надо? Code-style разрабатываешь?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>Тогда согласно твоему правилу константы нужно инициализировать используя скобки:
Нет, не надо. семантика значения не зависит от константности. Значение -- это число, строка, прямоугольник. Не значение -- это открытый файл, например.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>Здравствуйте, wander, Вы писали:
W>>ЗЫ. А можно ответный вопрос. Это что, у тебя там спор какой-то с кем-то по этому поводу?
I>Нет.
I>А можно все же ответ на мой вопрос? В необобщенном случае ты действительно напишешь int i = int();, вместо int i = 0;? Если нет, к чему был твой первый ответ?
Дык я вроде бы ответил уже. Вообще первый раз была шутка, думал поймешь. В необобщенном случае я так не напишу.
Здравствуйте, Erop, Вы писали:
E>Нет, не надо. семантика значения не зависит от константности.
Понимаю, просто обращаю внимание на недостаток твоего определения. Оно требует присваиваемости, а это не позволяет считать, что int const имеет семантику значения. Или "присваемый" означает у тебя не то же самое что "Assingable" в стандарте?
Здравствуйте, igna, Вы писали:
I> Или "присваемый" означает у тебя не то же самое что "Assingable" в стандарте?
Да. Так же, как и копируемый...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>Здравствуйте, fay, Вы писали:
fay>>Предпочитаю первый... Такая ошибка может обернуть веселыми минутами...
I>
fay>>int i(10);
fay>>int i[10];
I>
I>Честно говоря не вижу проблемы. Наверное можно сконструировать какой-нибудь (скорее искуственный) пример, но в большинстве случаев компилятор выдаст сообщение об ошибке когда попытаешься использовать целое вместо массива целых или наоборот.
При портировании с С — легко:
void test ( void *a );
int i1(10);
int i2[10];
test(&i1);
test(&i2);
I>> Или "присваемый" означает у тебя не то же самое что "Assingable" в стандарте?
E>Да. Так же, как и копируемый...
Прошу прощения, кратких ответов на отрицательные вопросы не понимаю. Ответ "нет" можно понимать как угодно, ответ "да" похоже и вовсе не имеет смысла. Поэтому переформулирую и прошу ответить еще раз:
"Присваемый" означает у тебя то же самое что "Assignable" в стандарте?
Здравствуйте, igna, Вы писали:
I>"Присваемый" означает у тебя то же самое что "Assignable" в стандарте?
да
И "копируемый" тоже обозначает аналогичное свойство из стандарта.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
I>>"Присваемый" означает у тебя то же самое что "Assignable" в стандарте?
E>да
const type не является Assignable, соответственно не имеет семантики значения. Читаем твое правило:
E>Я придерживаюсь простого формального правила: объекты с семантикой значения инициализирую через =, а объекты такой семантики лишённые через ()...
и инициализируем в соответствии с ним целую константу:
Здравствуйте, igna, Вы писали:
I>const type не является Assignable, соответственно не имеет семантики значения. Читаем твое правило:
А что, std::vector<const int> уже запрещён?..
I>и инициализируем в соответствии с ним целую константу: I>
I> int const n(123);
I>
Иди лесом. Я тебе уже писал, что const переменной на свойство типа иметь семантику значения не влияет. Просто это константное значение такого типа. Если тебе охота поупорожняться в цереброфилии, то общайся сам с собой...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>Здравствуйте, nik0lay, Вы писали:
N>>int i = 0; N>>экономя микросекунды на понимание кода читателями моей программы
I>Так. А std::complex, std::auto_ptr, boost::shared_ptr, std::string?
Ну тут понятно
std::complex<double> clVar( 3.0, -1.0 );
std::auto_ptr<MyStock> pStock( new MyStock( 12, 15, L"Выдача" ) );
boost::shared_array<wchar_t>( new wchar_t[MaxFileLen] );
А вот с std::wstring, честно, как попало. Даже не задумывался об этом.
Специально глянул в исходники — как пальцы стали, так и написал
Не Eropy
E>const переменной на свойство типа иметь семантику значения не влияет. Просто это константное значение такого типа.
Демагогия.
const в объявлении относится к типу, это часть типа, то есть в объявлении int const n, n это переменная типа int const, а не "константное значение" типа int, как пишет Erop.
Во-первых, как попало IMHO — плохо.
Во-вторых, никакой как-попалы я у тебя не заметил, инициализация strSQL использует скобки, strOwner не инициализируется.
Здравствуйте, igna, Вы писали:
I>const в объявлении относится к типу, это часть типа, то есть в объявлении int const n, n это переменная типа int const, а не "константное значение" типа int, как пишет Erop.
Если тебе надо понять, то ты поймёшь, IMHO. А если тебе надо поспорить...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>Да, запрещен.
Прикольно. Я пользовался как-то и не задумывался, что это не хорошо.
Интересно, зачем его запретили?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Если тебе надо понять, то ты поймёшь, IMHO. А если тебе надо поспорить...
Понять-то, я понял сразу, но потом спросил, нет ли у тебя формального определения. А формальное определение это как раз тот случай, где придирки к мелочам оправданы.
Здравствуйте, igna, Вы писали:
I>IMHO, в стандарте так получилось, никаких глубокомысленных причин запрета нет. Заодно, кстати, запретили std::set<const int>, что уж и вовсе неумно.
Спасибо, не знал, что маразм окрепчал настолько.
Ну я тогда, значит не стандартным понятием "присваемваемый" пользуюсь. Типа на константность и волатильность самого объекта не смотрю.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>Понять-то, я понял сразу, но потом спросил, нет ли у тебя формального определения. А формальное определение это как раз тот случай, где придирки к мелочам оправданы.
1) Придирки -- это скучно
2) Они не способствуют конструктивному духу дискуссии
3) Критикуешь -- предлагай, тем более, если ты понял
4) Я же тебе уже несколько раз написал, что константность переменной не учитываем. ТИпа так же как foo( int ) и foo( const int ) -- это одно и то же...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
I>Во-первых, как попало IMHO — плохо. I>Во-вторых, никакой как-попалы я у тебя не заметил, инициализация strSQL использует скобки, strOwner не инициализируется.
Здравствуйте, Erop, Вы писали:
E>foo( int ) и foo( const int ) -- это одно и то же...
В объявлении — да, в определении — нет.
Возвращаясь к твоему "простому формальному правилу" (объекты с семантикой значения инициализировать через =, а объекты такой семантики лишённые через ()), хочу спросить, верно ли я понял, что std::string следует инициализировать "через =" даже если это инициализация не другим std::string, а <творительный падеж>char const*</творительный падеж>?:
Здравствуйте, igna, Вы писали:
I>Возвращаясь к твоему "простому формальному правилу" (объекты с семантикой значения инициализировать через =, а объекты такой семантики лишённые через ()), хочу спросить, верно ли я понял, что std::string следует инициализировать "через =" даже если это инициализация не другим std::string, а <творительный падеж>char const*</творительный падеж>?:
I>
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>для единообразия.
Ну я же
double x = double( 5 );
не пишу...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Николай Ивченков, Вы писали:
НИ>Всюду, где возможно, я предпочитаю запись вида T x = y; — т.е. copy-initialization. Тем самым показывается использование неявного преобразования y к T, а значит, и родство между x и y — а именно: сущность y может быть использована там, где ожидается сущность типа T.
igna:
НИ>>Всюду, где возможно, я предпочитаю запись вида T x = y; — т.е. copy-initialization. Тем самым показывается использование неявного преобразования y к T, а значит, и родство между x и y — а именно: сущность y может быть использована там, где ожидается сущность типа T.
I>В том числе так?:
I>
vector<int> a = 10;
Конечно, это мой самый любимый код. Я ведь просто обожаю ill-formed программы, поэтому можешь не сомневаться, что под "где возможно" вовсе не подразумевалось, что программа должна успешно компилироваться.
Я вижу другой (более-менее разумный) вопрос, который тут имело бы смысл задать — это как поступить в случае с преобразующим конструктором, который следовало сделать явным (но таковым его не сделали и менять такое положение дел по каким-то соображениям не хотят)? Вероятно, я бы в этом случае использовал direct-initialization (как если бы конструктор был explicit) — если такая форма инициализации даст нужный эффект.
НИ>Здесь копирующий конструктор попросту не является viable function, и выбор падает на X(X const *). Что будет, если теперь заменить
НИ>
X x(X(0));
НИ>на
НИ>
X x = 0;
НИ>?
Насчёт этой ситуации удалось кое-что прояснить:
13.3.3.1/4:
However, when considering the argument of a user-defined conversion function that is a candidate by 13.3.1.3 when invoked for the copying of the temporary in the second step of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or 13.3.1.6 in all cases, only standard conversion sequences and ellipsis conversion sequences are allowed.
Вообще conversion function не может быть кандидатом по 13.3.1.3, но, видимо, там под "conversion function" имелся в виду не термин, определяемый в 12.3.2, а "constructor or conversion function" (где "conversion function" — это уже термин). Зря я раньше не дочитал до конца это предложение