#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
последних версий. Кто прав?
Откровенно говоря, мне эта идея - в не-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, но, как обычно, о том, насколько я неправ и как это соответствует стандарту, пусть расскажут гуру :)
Эта программа не должна компилироваться в соответствии со стандартом, так что 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:
Я пытался скомпилировать, но вылезла куча ошибок. Во первых, 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]’
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Виртуальный выделенный сервер (VDS) становится отличным выбором
хотел подключить OpenGL 4 стандартными средствами Windows SDK ко своему проекту на С++, не используя сторонние библиотеки на подобии glut, glfw и тд
Пишу программу для реверса символов в предложении (с помощью рекурсивной функции, обязательно)При первом же входе в функцию VS начинает орать...
Хочу получить результат, как, например, в Blender, в ортогональном режиме