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

Для чего "constexpr" полезен?

Я действительно не могу его использовать. Моя первая идея заключалась в том, что я мог использовать его для реализации "Design by Contract" без использования таких макросов, как это:

struct S
{   
    S(constexpr int i) : S(i) { static_assert( i < 9, "i must be < 9" ); }

    S(int i); //external defintion

    char *pSomeMemory;
};

Но это не скомпилировалось. Я думал, что мы также можем использовать его для ссылки на одну и ту же переменную без необходимости создания дополнительной памяти, когда мы хотим избежать get/seters, чтобы сделать экземпляры для одного члена из пользователей доступными только для чтения:

class S
{  
private:
    int _i;

public:
    const int & constexpr i = _i;
};

Но ни одно из вышеперечисленных фактически не скомпилировано. Может ли кто-нибудь дать мне некоторое представление о том, почему это ключевое слово вводилось?

4b9b3361

Ответ 1

Цель constexpr зависит от контекста:

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

    constexpr T value{args};
    

    Очевидно, для того, чтобы работать, args должны быть постоянными выражениями.

  • Для функций это означает, что вызов функции может привести к постоянному выражению. Результат результата функции constexpr вызывает постоянное выражение зависит от аргументов и определения функции. Непосредственная импликация заключается в том, что функция должна быть inline (она будет неявно сделана так). Кроме того, существуют ограничения на то, что можно сделать в такой функции. Для С++ 11 функция может иметь только один оператор, который для неконструкторов должен быть return -statement. Это ограничение было смягчено в С++ 14. Например, следующее определение функции constexpr:

    constexpr int square(int value) { return value * value; }
    

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

struct example {
    int value;
    constexpr example(int value): value(value) {}
};

int main() {
    constexpr example size{17};
    int array[size.value] = {};
}

Созданные значения constexpr могут использоваться везде, где ожидается постоянное выражение.

Ответ 2

Как я его вижу, constexpr - это способ объединить два языка С++ - тот, который выполняется во время выполнения, и тот, который выполняется во время компиляции. Программирование времени компиляции обычно называется метапрограммированием.

Сначала был C, с его макросами. Макросы были фактически небольшими программами, которые выполнял компилятор. У них были утверждения (называемые #ifdef), переменные (с #define). Там даже целый язык сценариев, который выполняется во время компиляции.

Когда С++ вышел, у него были макросы C и больше ничего. Затем появились шаблоны С++. Они ввели другой способ запуска кода времени компиляции. Мета-язык С++ был в основном функциональным, позволяя, например, делать циклы с хвостовой рекурсией.

В С++ 11 они решили, что метапрограммирование может выглядеть лучше, поэтому они представили constexpr. Теперь вы можете написать функции С++, которые также являются мета-функциями. В С++ 14 он становится лучше, потому что ограничения на функции constexpr были ослаблены.

Ответ 3

Хотя это объясняется более подробно в "Constexpr - Обобщенные константные выражения в С++ 11", статья Алекса Аллана, я упрощу его с помощью нескольких простых точек.


РЕДАКТИРОВАТЬ: Извините, я был виноват в том, что мне кажется, что я был автором этих вопросов, и я исправил себя и изменил различные части и добавил цитаты, чтобы избежать плагизма.


Простое объяснение полезности:

  • Сначала с помощью спецификатора Constexpr значение функции или переменной может быть во время компиляции.
  • Еще одно преимущество Constexpr Specifier заключается в том, что он может заменить макросы функциями
  • Constexpr также пригодится для метапрограммирования шаблонов.

Финал

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

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

Дополнительно:

Такие переменные и функции могут использоваться тогда, когда допускаются только компиляции констант времени. Спецификатор constexpr, используемый в объявлении объекта, подразумевает const. Спецификатор constexpr, используемый в объявлении функции, подразумевает inline. (CPP 1)

Некоторые простые правила для запоминания -

Правила:

  • Он должен состоять из одного оператора return (за некоторыми исключениями)
  • Он может вызывать только другие функции constexpr
  • Он может ссылаться только на constexpr глобальных переменных (Allain 6)

Дополнительно:

Правила конструктора Constexpr:

  • каждый из его параметров должен быть литеральным типом
  • класс не должен иметь виртуальных базовых классов
  • конструктор не должен иметь функцию-try-block (CPP 6)

Цитирование

Allain, Alex, "Constexpr - Обобщенные константные выражения в С++ 11", Unspecified Date, " http://www.cprogramming.com/c++11/c++11-compile-time-processing-with-constexpr.html"

CPP, "Constexpr Specifier", 16 декабря 2014 года, http://en.cppreference.com/w/cpp/language/constexpr

Ответ 4

Ответа на вопрос "Может ли кто-нибудь дать мне некоторое представление о том, почему вводилось ключевое слово constexpr?"

Современный С++ поддерживает два типа неизменяемости.

1) const

2) constexpr.

constexper будет оцениваться во время компиляции. Он используется для указания константы и позволяет размещать данные в памяти, где она может быть повреждена.

Пример 1:

void UseConstExpr(int temp)
{
    // This code snippet is OK
    constexpr int y = max + 300;
    std::cout << y << std::endl;
    // This code snippet gives compilation error
    // [ expression must have a constant value]
    constexpr int z = temp + 300;

}

Пример 2:

int addVector(const std::vector<int>& inVect)
{
    int sum = 0;
    for ( auto& vec : inVect)
    {
        sum += vec;
    }
    std::cout << sum << std::endl;
    return sum;
}

int main()
{
    // vInt is not constant
    std::vector<int> vInt = { 1,2,3,4,5,6 }; 
    // This code snippet is OK
    // because evaluated at run time
    const int iResult = addVector(vInt);
    // Compiler throws below error
    // function call must have a constant value in a constant expression
    // because addVector(vInt) function is not a constant expression
    constexpr int iResult = addVector(vInt);
    return 0;
}

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