Я с этим его мнением не согласен. Кстати, у Саттера допущена грубая неточность.
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 нужно инициализировать по разному. Я правильно понял?