constexpr начало std :: array - PullRequest
       46

constexpr начало std :: array

0 голосов
/ 24 октября 2018

У меня проблемы с пониманием, почему и gcc-8.2.0, и clang-7.0.0 отклоняют следующий код (действующий код здесь ):

#include <array>

int main() {

    constexpr std::array<int,3> v{1,2,3};
    constexpr auto b = v.begin(); // error: not a constexpr 
    return 0;
}

с ошибкой

error: '(std::array<int, 3>::const_pointer)(& v.std::array<int,3>::_M_elems)' 
is not a constant expression (constexpr auto b = v.begin();)

Согласно ru.cppreference.com , функция-член begin() объявлена ​​constexpr.Это ошибка компилятора?

1 Ответ

0 голосов
/ 24 октября 2018

Итак, давайте отступим std::array, чтобы сделать это немного проще:

template <typename T, size_t N>
struct array {
    T elems[N];

    constexpr T const* begin() const { return elems; }
};

void foo() {
    constexpr array<int,3> v{{1, 2, 3}};
    constexpr auto b = v.begin(); // error
}

constexpr array<int, 3> global_v{{1, 2, 3}};
constexpr auto global_b = global_v.begin(); // ok

Почему b ошибка, но global_b в порядке?Аналогично, с чего бы b стало нормально, если бы мы объявили v равным static constexpr?Основная проблема заключается в указателях.Чтобы иметь постоянное выражение, которое является указателем, оно должно всегда указывать на одну известную постоянную вещь.Это на самом деле не работает для локальных переменных без статической длительности хранения, поскольку они имеют принципиально изменяемый адрес.Но для статических или глобальных функций локальных функций они имеют один постоянный адрес, так что вы можете взять на них постоянный указатель.

В стандарте от [expr.const] / 6 :

A константное выражение является либо основным константным выражением glvalue, которое относится кобъект, который является разрешенным результатом постоянного выражения (как определено ниже) или основного постоянного константного выражения, значение которого удовлетворяет следующим ограничениям:

  • , если значение является объектом типа класса, [...]
  • , если значение имеет тип указателя, оно содержит адрес объекта со статической продолжительностью хранения , адрес после конца такого объекта ([expr.add]), адрес функции или значение нулевого указателя и
  • [...]

b - это не то, что во втором пуле, так что это не удается.Но global_b удовлетворяет условию жирного шрифта - как и b, если бы v было объявлено static.

...