constexpr вызов функции size() у ссылки

181
28 апреля 2019, 20:40
#include <iostream>
#include <array>

template<typename array_type>
auto array_size(const array_type& arr) {
    constexpr auto size = arr.size(); // действительно ли size будет constexpr?
    return size;
}

int main() {
    constexpr std::array arr = {1, 2, 3, 4, 5};
    std::cout << array_size(arr);
}

Правда ли что в этой программе size является constexpr, ведь мы вызываем функцию-член size() у ссылки? Интересно, что программа компилируется gcc, но не компилируется clang последних версий. Кто прав?

Answer 1

Откровенно говоря, мне эта идея - в не-constexpr функции иметь constexpr-переменную - не очень нравится. Вот такой вариант мне представляется более корректным и согласованным.

template<typename array_type>
constexpr auto array_size(const array_type& arr) {
    auto size = arr.size();
    return size;
}

int main() {
    constexpr std::array arr = {1, 2, 3, 4, 5};
    constexpr auto as = array_size(arr);
    std::cout << as;
}

Так что мне кажется, что в вашем случае формально прав clang, но, как обычно, о том, насколько я неправ и как это соответствует стандарту, пусть расскажут гуру :)

Answer 2

Эта программа не должна компилироваться в соответствии со стандартом, так что clang прав.

Чтобы объявить переменную size со спецификатором constexpr, надо инициализировать её с помощью constant expression.

dcl.constexpr#9:

In any constexpr variable declaration, the full-expression of the initialization shall be a constant expression.

Однако выражение arr.size() не является core constant expression.

expr.const#2.11:

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

  • ...
  • an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either

    • ...
    • ...
  • ...

Здесь e = arr.size(), а arr является "an id-expression that refers to a variable of reference type", не имеющим "preceding initialization".

Т.к. выражение не является core constant expression, то оно не является и constant expression.

expr.const#6:

A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:

  • ...
  • ...
  • ...
Answer 3

Я пытался скомпилировать, но вылезла куча ошибок. Во первых, array это шаблон, вы не указали тип и размер.

constexpr std::array arr = {1, 2, 3, 4, 5};
error: invalid use of template-name ‘std::array’ without an argument list

Дальше пытался в функции принять аргумент как constexpr - не вышло.

auto array_size(constexpr array_type& arr) {  
error: a parameter cannot be declared ‘constexpr’

Если аргумент просто const получить constexpr размер не получилось.

error: ‘arr’ is not a constant expression
constexpr auto size = arr.size(); // действительно ли size будет constexpr?

Осталось узнать константный ли реальный размер.

constexpr std::array < int , 10 > arr_global = {1, 2, 3, 4, 5};
...
  constexpr auto size = arr_global.size(); // действительно ли size будет constexpr?
  return size;

У глобального массива arr_global размер действительно получили constexpr. Осталось посмотреть реальный код :

g++ -Wall -Wextra -Wpedantic -std=c++11 -Os -S -fverbose-asm return_constexpr.cpp

Функция main решила после оптимизации, что функция array_size больше не нужна на любые массивы, и выводит на экран константы.

std::cout << array_size(arr); 
std::cout << array_size_global();
movl    $10, %esi   #,
movl    $_ZSt4cout, %edi    #,
call    _ZNSolsEm   #
movl    $10, %esi   #,
movl    $_ZSt4cout, %edi    #,
call    _ZNSolsEm   #

auto array_size_static(const std::array < int , 10 >& arr) {  
  const auto size = arr.size(); // действительно ли size будет constexpr?
  return size;}
movl    $10, %eax   #,
ret

auto array_size_global() {  
    constexpr auto size = arr_global.size(); // действительно ли size будет constexpr?
    return size; }
movl    $10, %eax   #,
ret
auto vector_size_static(const std::vector < int > & vec ) {  
  const auto size = vec.size(); // действительно ли size будет constexpr?
  return size;}
    movq    8(%rdi), %rax   # vec_2(D)->D.34470._M_impl._M_finish, D.36351
    subq    (%rdi), %rax    # vec_2(D)->D.34470._M_impl._M_start, D.36351
    sarq    $2, %rax    #, D.36351
    ret

В итоге вывод: для массивов будет constexpr в коде. Шаблон функции от массива , который всего лишь возвращает размер не компилируется. Я лично не вижу повода для такой ошибки.

template  < typename T , std :: size_t n >  
auto my_array_size  ( const Array < T , n >  & arr ) { return n ; }
size_t constexpr mys2 = my_array_size<int,15> ( mya ) ;
error: call to non-constexpr function 
‘auto my_array_size(const Array<T, n>&) [with T = int; long unsigned int n = 15ul]’
READ ALSO
OpenGL 4 со стандартного Windows SDK

OpenGL 4 со стандартного Windows SDK

хотел подключить OpenGL 4 стандартными средствами Windows SDK ко своему проекту на С++, не используя сторонние библиотеки на подобии glut, glfw и тд

158
Stack overflow c++ (где моя память?)

Stack overflow c++ (где моя память?)

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

152
нагрузка на CPU из-за потоков в dll c++

нагрузка на CPU из-за потоков в dll c++

есть такого типа код:

136
Как использовать glm::ortho?

Как использовать glm::ortho?

Хочу получить результат, как, например, в Blender, в ортогональном режиме

145