В этом коде есть что-то совершенно неочевидное:
float a = 1.;
const float & x = true ? a : 2.; // Note: `2.` is a double
a = 4.;
std::cout << a << ", " << x;
вывод clang и gcc:
4, 1
Можно было бы наивно ожидать, что одно и то же значение будет напечатано дважды, но это не так. Проблема здесь не имеет ничего общего со ссылкой. Существуют некоторые интересные правила, определяющие тип ? :
. Если два аргумента имеют различный тип и могут быть отброшены, они будут использовать временный. Ссылка будет указывать на временный ? :
.
Приведенный выше пример компилируется отлично, и он может или не может выдавать предупреждение при компиляции с -Wall
в зависимости от версии вашего компилятора.
Вот пример того, как легко получить это неправильно в законно выглядящем коде:
template<class Iterator, class T>
const T & min(const Iterator & iter, const T & b)
{
return *iter < b ? *iter : b;
}
int main()
{
// Try to remove the const or convert to vector of floats
const std::vector<double> a(1, 3.0);
const double & result = min(a.begin(), 4.);
cout << &a[0] << ", " << &result;
}
Если ваша логика после этого кода предполагает, что любые изменения на a[0]
будут отражены на result
, это будет неправильно в случаях, когда ?:
создает временную. Кроме того, если в какой-то момент вы делаете указатель на result
, и вы используете его после того, как result
выходит за пределы области видимости, произойдет ошибка сегментации, несмотря на то, что ваш оригинальный a
не вышел из области видимости.
Я чувствую, что есть серьезные причины НЕ использовать эту форму помимо "проблем с ремонтопригодностью и чтением", упомянутых здесь здесь, особенно при написании шаблонного кода, где некоторые из ваших типов и их const'ness может оказаться вне вашего контроля.
Итак, мой вопрос: безопасно ли использовать const &
для тернарных операторов?
P.S. Бонусный пример 1, дополнительные осложнения (см. Также здесь):
float a = 0;
const float b = 0;
const float & x = true ? a : b;
a = 4;
cout << a << ", " << x;
вывод clang:
4, 4
gcc 4.9.3 вывод:
4, 0
С clang этот пример компилируется и работает как ожидалось, но с последними версиями gcc (
P.S.2 Бонусный пример 2, отличный для интервью;):
double a = 3;
const double & a_ref = a;
const double & x = true ? a_ref : 2.;
a = 4.;
std::cout << a << ", " << x;
выход:
4, 3