Skip to content

constexpr specifier

constexpr应该是constant expression的缩写,显然它是为了支持c++的constant expression特性而添加的,显然,它需要杜绝所有的run-time概念。

What's in C++ # constexpr

wikipedia C++11#constexpr – Generalized constant expressions,这一段所总结地非常好。

wikipedia Compile time function execution#Examples

wikipedia Template metaprogramming#Compile-time class generation

In C++11 and C++20, constexpr and consteval were introduced to let the compiler execute code. Using constexpr and consteval, one can use the usual recursive factorial definition with the non-templated syntax.

上述两篇中,给出的example是非常好的,非常具有启发性。

constexpr发展史

C++11

引入了constexpr

C++14

1、stackoverflow Difference between constexpr and const # A

As of C++14, the rules are more relaxed, what is allowed since then inside a constexpr function: asm declaration, a goto statement, a statement with a label other than case and default, try-block, the definition of a variable of non-literal type, definition of a variable of static or thread storage duration, the definition of a variable for which no initialization is performed. 2、wikipedia C++14 # Relaxed constexpr restrictions

C++17

constexpr if statements

参见 C++\Language-reference\Statements\Selection-statements\Constexpr-if章节。

C++20

cppreference C++20

further relaxed constexpr

具体参见原文。

cppreference constexpr specifier

Explanation

The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time.

NOTE: 这段话是非常核心地所在

Such variables and functions can then be used where only compile time constant expressions are allowed (provided that appropriate function arguments are given).

NOTE: 需要对最后一句话进行说明:它的意思是:constexpr function的入参必须是能够在compile-time获得的。

constexpr variable

A constexpr variable must satisfy the following requirements:

NOTE: 原文给出了**constexpr variable**的若干requirements,总的来说,这些requirements是为了保证这个variable的值是可以在compile time evaluate得到的,所以它需要排除所有的run time 概念。

Examples

galowicz What is a Type Trait?

template <bool X>
struct not
{
    static constexpr bool value {!X};
};
static constexpr not(bool x) 
{
    return !x;
}

constexpr function

Example: Factorial

来源: 维基百科Compile time function execution#Examples

C++11之前:

#include<iostream>
template <int N>
struct Factorial {
  enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> {
  enum { value = 1 };
};

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void Foo() {
  int x = Factorial<0>::value;  // == 1
  std::cout<<x<<std::endl;
  int y = Factorial<4>::value;  // == 24
  std::cout<<y<<std::endl;    
}

int main()
{
    Foo();
}

编译: g++ test.cpp,输出如下

1
24

C++11

#include <cstdio>

constexpr int Factorial(int n) { return n ? (n * Factorial(n - 1)) : 1; }

constexpr int f10 = Factorial(10);

int main() {
  printf("%d\n", f10);
  return 0;
}

编译: g++ -std=c++11 test.cpp,输出如下

3628800

C++14

// Iterative factorial at compile time.
constexpr int Factorial(int n)
{
    int result = 1;
    while (n > 1)
    {
        result *= n--;
    }
    return result;
}

int main()
{
    constexpr int f4 = Factorial(4);  // f4 == 24
}

NOTE: 编译 g++ -std=c++11 test.cpp

test.cpp: 在函数‘constexpr int Factorial(int)’中:
test.cpp:10:1: 错误:body of constexpr function constexpr int Factorial(int) not a return-statement
 }
 ^
test.cpp: 在函数‘int main()’中:
test.cpp:14:32: 错误:‘constexpr int Factorial(int) called in a constant expression
  constexpr int f4 = Factorial(4);  // f4 == 24

Example

来源: stackoverflow Using a constexpr array size function

#include "stddef.h"
#include "stdio.h"
#include <iostream>
#include <typeinfo>

typedef ptrdiff_t Size;

using Size = ptrdiff_t;

template<class Type, Size n>
constexpr auto n_items(Type (&)[n]) -> Size
{
    return n;
}

// Example 1
void foo()
{
    int const x[] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
    constexpr Size n = n_items(x);
    int y[n] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
    for (auto&& i : y)
    {
        std::cout << i << std::endl;
    }
    // Using y here.
}

int main()
{
    foo();
}
// g++ --std=c++11 test.cpp

Example

来源: cppreference sizeof... operator make_array

constexpr constructor

NOTE: 在cppreference Constructors and member initializer lists#Explanation 中有这样的描述:

The constructors with a constexpr specifier make their type a LiteralType.

这段话,说明了在C++中,如何构建literal type。

Example

参见C++\Language-reference\Expressions\Constant-expressions\constexpr\Literal-type

microsoft constexpr (C++)

TODO

stackoverflow When should you use constexpr capability in C++11?