Когда параметр «возврат по ссылке» или «передача по ссылке» совместим с constexpr? - PullRequest
2 голосов
/ 13 февраля 2012

Функции, отмеченные как constexpr, должны быть неизменными чистыми функциями. Из сообщения "std :: max () и std :: min () not constexpr" вы не можете повторно направить вход const-reference в качестве вывода, так как для этого потребуется параметр иметь постоянство. Но можете ли вы взять параметр по const -ссылке, если вы не переадресовали его?

// Is this still constexpr?
// (Assuming that std::complex is constexpr-safe, as it's supposed to be.)
constexpr
int  MySum( std::complex<double> const &a, std::complex<double> const &b )
{ return static_cast<int>( a.real() + b.real() ); }

И наоборот, вы можете вернуть const-ссылку на подобъект типа constexpr -enabled?

template <typename T>
class MyComplex
{
    T  c_[ 2 ];
public:
    constexpr MyComplex( T r = T(), T i = T() )
    : c_{ r, i }
    {}

    // Is this actually constexpr?
    constexpr T const &  operator[]( unsigned l ) //const
    { return c_[ l ]; }

    // Can't be constexpr
    T &  operator[]( unsigned l )  { return c_[ l ]; }
};

Или даже возвращаемые субобъекты должны быть по значению?

(Извините, если это просто, но все, что я нашел, танцует вокруг этой точки, фактически не будучи окончательным.)

Ответы [ 2 ]

4 голосов
/ 13 февраля 2012

Стандарт довольно ясно показывает, что разрешено в функции constexpr:

§7.1.5 [dcl.constexpr] p3

Определение функции constexpr должно удовлетворять следующим ограничениям:

  • [...]
  • его тип возвращаемого значения должен быть литеральным типом;
  • каждый из его типов параметров должен быть литеральным типом;
  • [...]

§3.9 [basic.types] p10

Тип литеральный тип , если это:

  • скалярный тип; или
  • ссылочный тип; или
  • тип класса (раздел 9), который имеет все следующие свойства:
  • у него есть тривиальный деструктор,
    • каждый вызов конструктора и полное выражение в инициализаторах скобок или равных для нестатических данных члены (если есть) является константным выражением (5.19),
    • это агрегатный тип (8.5.1) или имеет хотя бы один конструктор constexpr или шаблон конструктора это не конструктор копирования или перемещения, а
    • имеет все нестатические члены-данные и базовые классы литеральных типов; или
  • массив литерального типа.

Как таковые, да, вы можете иметь опорные параметры, даже ссылки на неконстантные. Параметры функции constexpr ограничены другим способом. Полный, исчерпывающий список можно найти под §5.19 [expr.const] p2. Вот выдержка из того, что делает объявленную функцию constexpr не такой уж constexpr:

A условное выражение является основным константным выражением , если только оно не включает одно из следующего в качестве потенциально вычисляемого подвыражения (3.2), но подвыражения логического И (5.14), логического ИЛИ (5.15) и условные (5.16) операции, которые не оцениваются, не учитываются [ Примечание: Перегруженный оператор вызывает функцию. - Конечная заметка ]:

(Последний бит о логических операторах просто означает, что его неоцененная часть (из-за оценки короткого замыкания) не является частью операций, определяющих, действительно ли функция constexpr.)

  • [...]
  • динамическое приведение (5.2.7);
  • a reinterpret_cast (5.2.10);
  • вызов псевдодеструктора (5.2.4);
  • операции увеличения или уменьшения (5.2.6, 5.3.2);
  • выражение typeid (5.2.8), операнд которого имеет тип полиморфного класса;
  • a new-expression (5.3.4);
  • a выражение для удаления (5.3.5);
  • вычитание (5.7), где оба операнда являются указателями;
  • оператор отношения (5.9) или равенства (5.10), где результат не указан;
  • назначение или составное назначение (5.17); или
  • [...]
1 голос
/ 02 марта 2012

Основная проблема 1454 * Разрешение 1002 * изменяет правило, на которое Йоханнес ссылается в своем ответе, на вопрос std :: max .При текущем разрешении этой проблемы (которое реализуется как g ++, так и clang), функциям constexpr разрешено возвращать, посредством ссылки, любое значение l, которое они могут вычислить.

...