Меня смущает функция constexpr?

В C ++ Primer, пятое издание, §6.5.2:

Функция constexpr определяется как любая другая функция, но должна соответствовать определенным ограничениям: Тип возвращаемого значения и тип каждого параметра в должны быть буквальным типом (§2.4.4, стр. 66), а тело функции должно содержать ровно один оператор возврата

но еще одно предложение в этой главе (стр. 239):

Функция constexpr может возвращать значение, которое не является константой.

// scale(arg) is a constant expression if arg is a constant expression
constexpr size_t scale(size_t cnt) { return new_sz() * cnt; }

Это противоречивое резюме? Я запутался в этом.
Тип возвращаемого значения scale - это буквальный тип?
Обновление: в чем разница между буквальным типом и константой?


person Ocxs    schedule 05.03.2015    source источник
comment
Литеральный тип не обязательно означает целочисленную константу, например 5. Стандарт определяет, что такое буквальный тип, но я не могу сейчас найти его. Вот его страница cppreference.   -  person    schedule 05.03.2015
comment
Что вы думаете противоречивого? Типы должны быть буквальными (например, size_t), а значения не должны быть постоянными. Предположительно, §2.4.4, с. 66 описывает буквальные типы - это не означает постоянный, если вы так думали.   -  person Mike Seymour    schedule 05.03.2015


Ответы (3)


Это не противоречит. Помимо требования о том, что возвращаемый тип должен быть «буквального типа», черновик стандарта утверждает, что вызов функции constexpr не обязательно должен появляться в константном выражении. Из чернового стандарта C ++ 11:

§7.1.5 / 7 Вызов функции constexpr дает тот же результат, что и вызов эквивалентной функции, отличной от constexpr, во всех отношениях, за исключением того, что вызов функции constexpr может появиться в константном выражении.

person Community    schedule 05.03.2015

Прежде всего, как я полагаю, автор имел в виду, что функция constexpr не должна приводить к постоянное выражение, которое может вычисляться во время компиляции.

Функция constexpr выдаст константное выражение, только если аргументы функции также являются константными выражениями и в комментарии сразу после него сказано именно это:

// scale(arg) is a constant expression if arg is a constant expression

и примеры, которые следуют сразу после, также демонстрируют это поведение:

int arr[scale(2)]; // ok: scale(2) is a constant expression
int i = 2; // i is not a constant expression
int a2[scale(i)]; // error: scale(i) is not a constant expression

В C ++ (в отличие от C99) размер массива должен быть постоянным выражением, поэтому последний случай является ошибкой, поскольку аргумент scale не является постоянным выражением.

Это отличается от типа возвращаемого значения функции, который должен быть литеральным типом который может быть любым из следующего:

  • void (начиная с C ++ 14) (чтобы функции constexpr могли возвращать void)
  • скалярный тип, который включает арифметические типы, типы перечисления, типы указателей, указатели на типы членов, std :: nullptr_- t и версии этих типов с квалификацией cv)
  • ссылочный тип
  • массив буквального типа
  • class type that has all of the following properties:
    • has a trivial destructor,
    • is either
      • an aggregate type
      • тип с хотя бы одним конструктором constexpr (возможно, шаблоном), который не является конструктором копирования или перемещения
    • все нестатические элементы данных и базовые классы имеют энергонезависимые литеральные типы.
person Shafik Yaghmour    schedule 06.03.2015

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

int a1 = 5;
std::array<int, a1> arr1; // error, a is variable

const int a2 = 5;
std::array<int, a2> arr2; // OK

int f1() { return 3; }
std::array<int, f1()> arr3; // error, compiler doesn't know it is const 3

constexpr int f2() { return 3; }
std::array<int, f2()> arr4; // OK

Позже вы также сможете:

constexpr int f3() { return f1() + 1; } // error, f1 is not constexpr

constexpr int f4() { return f2() + 1; } // OK
std::array<int, f4()> arr5; // OK

Теперь об ограничении буквальных типов: аргументы функции и типы результатов должны быть буквальными типами (Need разъяснение по определению типа литерала), применяется то же ограничение, что и аргументы шаблона (известные в типах компиляции).

constexpr std::string f5() { return "hello"; } // error, 
                   // std::string is not literal type

constexpr const std::string& f6() { 
  static const std::string s = "hello";
  return s;
}

template<const std::string& s> SomeClass { ... };
SomeClass<f6()> someObject;
person Mux    schedule 05.03.2015
comment
Это не отвечает на заданный вопрос. Это может иметь отношение к названию вопроса, но вы действительно должны прочитать вопрос полностью. - person ; 05.03.2015
comment
извини, в следующий раз будем внимательнее - person Mux; 05.03.2015