Подтвердить что ты не робот

Является ли constexpr "подсказкой" (например, inline) или "запросом привязки" к компилятору?

Является ли constexpr индикатором для компилятора или он управляет поведением?

Ниже приведен пример:

template<typename T> 
std::size_t constexpr getID() { return typeid(T).hash_code(); }

hash_code - постоянная времени выполнения, но этот фрагмент компилируется, даже если оценка времени компиляции запрашивается с помощью constexpr. Только после использования возвращаемого значения, когда ожидается постоянная времени компиляции, заметим, что этот не используется в качестве функции constexpr.

Итак, constexpr "подсказка" (как и ключевое слово inline) или "запрос привязки" к компилятору?

4b9b3361

Ответ 1

На странице С++ 11 Wiki:

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

Таким образом, спецификатор constexpr выражает возможность оценивать что-то во время компиляции и подлежит некоторым ограничениям при использовании.


Для вашего конкретного фрагмента мне кажется, что ограничение С++ 11:

точно один оператор return, содержащий только литералы, constexpr переменные и функции

не выполняется, поскольку hash_code определяется как:

size_t hash_code() const;

В этом случае стандартный черновик n3242 говорит:

Для функции constexpr, если значения аргументов функции не существуют что подстановка функции вызовет постоянство выражение (5.19), программа плохо сформирована; не требуется диагностика.

Я считаю, что ваш пример здесь подходит.

Ответ 2

Является ли constexpr "подсказкой" (например, inline) или "запросом привязки" к компилятору?

Это не так. Забудьте о том, когда он будет оценен. Все (с несколькими незначительными исключениями, особенно с участием volatile) оценивается всякий раз, когда компилятор считает необходимым создавать поведение абстрактной машины С++. Больше не о чем говорить, когда оцениваются вещи.

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

Если не о времени компиляции и времени выполнения, что такое constexpr, то?

constexpr позволяет обрабатывать вещи как постоянные выражения. Все, что помечено как constexpr, должно иметь возможность выражать некоторое выражение в некотором роде.

В случае функций они могут создавать постоянные выражения с некоторыми аргументами, но не другие. Но до тех пор, пока существует некоторый набор аргументов, которые могут привести к постоянному выражению, функция может быть отмечена constexpr. Если такой набор аргументов используется в вызове функции, это выражение является постоянным выражением. Означает ли это, что он оценивается во время компиляции? См. Выше. Он оценивался, когда компилятор сочтет это уместным. Единственное, что это означает, это то, что вы можете использовать его в контексте, требующем постоянного выражения.

Для переменных либо они являются постоянными выражениями, либо нет. У них нет аргументов, поэтому, если constexpr, их всегда нужно инициализировать с помощью константных выражений.

TL; DR: constexpr относится к пометке вещей как к использованию в постоянных выражениях, а не о принятии решения о том, когда их оценивать.


С этой точки зрения, похоже, ваш шаблон функции плохо сформирован. Нет никакого набора аргументов, которые могли бы привести к постоянному выражению. Стандарт не требует для этого диагностики.

Ответ 3

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

 constexpr int func(int a) { return a+2; }

 char x[func(10)];

Если func вызывается во время выполнения, компилятор может оценить это выражение раньше, если это возможно. Но это не обязательно, но обычно выполняется, если вход также const.

Также важно иметь конструкторы constexpr. Это единственный шанс получить объекты не POD для объектов constexpr.

    class Point
    {   
        private:    
            int x;
            int y;
        public:
            constexpr Point( int _x, int _y) : x(_x), y(_y) {}  
            constexpr int GetX() const { return x; }
    };  

    constexpr Point p{1,2};

    int main()
    {   

        char i[p.GetX()];
        return 0;
    }   

Ответ 4

Полный ответ на ваш вопрос имеет два аспекта:

  • Функция constexpr может быть оценена только во время компиляции, когда все аргументы могут быть оценены во время компиляции. Его все еще можно использовать как нормальная функция, которая оценивается во время выполнения.

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

Вы можете присвоить хэш-код переменной constexpr, а затем получить вывод компилятора:

#include <typeinfo>
#include <array>

template<typename T> 
std::size_t constexpr getID() { 

    return []() {constexpr size_t id = typeid(T).hash_code(); return id;}(); }

int main() {
    // both statement generate compiler errors
    //std::array<int, typeid(int).hash_code()> a;
    //constexpr size_t y = typeid(int).hash_code();

    size_t x = getID<int>();
}