C++ “constexpr”和“const”之间的区别`
C++ “constexpr”和“const”之间的区别`,c++,c++11,constants,constexpr,C++,C++11,Constants,Constexpr,constepr和const之间有什么区别 什么时候我可以只使用其中一个 我什么时候可以同时使用这两种方法?我应该如何选择一种 const适用于变量,并且防止它们在代码中被修改 constexpr告诉编译器,这个表达式会产生一个编译时常量值,因此它可以用于数组长度、赋值给const变量等地方。Oli给出的例子非常好 基本上,它们是两个不同的概念,可以(也应该)一起使用。基本含义和语法 这两个关键字都可以用于对象和函数的声明。应用于对象时的基本区别是: const将对象声明为常量。这意味着一旦
constepr
和const
之间有什么区别
- 什么时候我可以只使用其中一个李>
- 我什么时候可以同时使用这两种方法?我应该如何选择一种
const
适用于变量,并且防止它们在代码中被修改
constexpr
告诉编译器,这个表达式会产生一个编译时常量值,因此它可以用于数组长度、赋值给const
变量等地方。Oli给出的例子非常好
基本上,它们是两个不同的概念,可以(也应该)一起使用。基本含义和语法
这两个关键字都可以用于对象和函数的声明。应用于对象时的基本区别是:
将对象声明为常量。这意味着一旦初始化,该对象的值就不会改变,编译器可以利用这一事实进行优化。它还有助于防止程序员编写代码来修改初始化后不需要修改的对象const
将对象声明为适合在标准称为常量表达式的对象中使用。但是请注意,constexpr
并不是实现这一点的唯一方法constexpr
只能用于非静态成员函数,不能用于一般函数。它保证成员函数不会修改任何非静态数据成员(可变数据成员除外,可以修改)const
可以与成员函数、非成员函数以及构造函数一起使用。它声明适合在常量表达式中使用的函数。编译器仅在函数满足某些标准(7.1.5/3,4)时才会接受它,最重要的是(†):constexpr
- 函数体必须是非虚拟的并且非常简单:除了typedef和静态断言之外,只允许使用一个
语句。对于构造函数,只允许初始化列表、typedefs和静态断言。(return
和=default
也是允许的。)=delete
- 从C++14开始,规则更为宽松,从那时起在constexpr函数中允许的是:
声明、asm
语句、带有标签而不是goto
和case
的语句、try block、非文字类型变量的定义、,静态或线程存储持续时间变量的定义,不执行初始化的变量的定义default
- 参数和返回类型必须是文本类型(即,一般来说,非常简单的类型,通常是标量或聚合)
- 函数体必须是非虚拟的并且非常简单:除了typedef和静态断言之外,只允许使用一个
constexpr
声明了两个对象以及适合在常量表达式中使用的函数。常量表达式不仅仅是常量:
- 它可用于需要编译时计算的地方,例如模板参数和数组大小说明符:
这是可能的,因为template<int N> class fixed_size_list { /*...*/ }; fixed_size_list<X> mylist; // X must be an integer constant expression int numbers[X]; // X must be an integer constant expression
是常量,并且在声明时使用文本初始化,即使未声明N
,也满足常量表达式的条件constexpr
constexpr
?
- 类似于上面的
的对象可以用作常量表达式,而无需声明N
。这适用于以下所有对象:constexpr
const
- 整型或枚举型,以及
- 在声明时使用本身是常量表达式的表达式初始化
- 要使函数
constexpr
;仅仅满足常量表达式函数的标准是不够的。例如:
int main()
{
const int N = 3;
int numbers[N] = {1, 2, 3}; // N is constant expression
}
template<int N>
class list
{ };
constexpr int sqr1(int arg)
{ return arg * arg; }
int sqr2(int arg)
{ return arg * arg; }
int main()
{
const int X = 2;
list<sqr1(X)> mylist1; // OK: sqr1 is constexpr
list<sqr2(X)> mylist2; // wrong: sqr2 is not constexpr
}
与
constexpr int N = 5;
但是,请注意,在某些情况下,每个关键字都引用声明的不同部分:
static constexpr int N = 3;
int main()
{
constexpr const int *NP = &N;
}
这里,NP
被声明为地址常量表达式,即本身是常量表达式的指针。(当通过将地址运算符应用于静态/全局常量表达式来生成地址时,这是可能的。)此处,需要constepr
和const
:constepr
始终指声明的表达式(此处NP
),而const
指int
(它声明一个指向常量的指针)。删除常量将导致表达式非法(因为(a)指向非常量对象的指针不能是常量表达式,(b)&N
实际上是指向常量的指针)
B.在成员函数声明中。在C++11中,constepr
意味着const
,而在C++14和C++17中则不是这样。在C++11下声明的成员函数
constexpr void f();
需要声明为
constexpr void f() const;
< C++ > 14,以作为代码< >代码>函数> >函数> < /P> < P>根据Bjarne Stroustrup的《C++编程语言第四EDITNN》一书
•const:大致意思是“我保证不改变此值”(
constexpr void f() const;
const int dmv = 17; // dmv is a named constant
int var = 17; // var is not a constant
constexpr double max1 = 1.4*square(dmv); // OK if square(17) is a constant expression
constexpr double max2 = 1.4∗square(var); // error : var is not a constant expression
const double max3 = 1.4∗square(var); //OK, may be evaluated at run time
double sum(const vector<double>&); // sum will not modify its argument (§2.2.5)
vector<double> v {1.2, 3.4, 4.5}; // v is not a constant
const double s1 = sum(v); // OK: evaluated at run time
constexpr double s2 = sum(v); // error : sum(v) not constant expression
constexpr double square(double x) { return x∗x; }
const int mx = numeric_limits<int>::max(); // OK: runtime initialization
int arr[mx]; // error: “constant expression required”
constexpr int max() { return INT_MAX; } // OK
constexpr long long_max() { return 2147483647; } // OK
constexpr bool get_val()
{
bool res = false;
return res;
} // error: body is not just a return statement
constexpr int square(int x)
{ return x * x; } // OK: compile-time evaluation only if x is a constant expression
const int res = square(5); // OK: compile-time evaluation of square(5)
int y = getval();
int n = square(y); // OK: runtime evaluation of square(y)
struct S
{
constexpr int two(); // constant-expression function
private:
static constexpr int sz; // constant-expression object
};
constexpr int S::sz = 256;
enum DataPacket
{
Small = S::two(), // error: S::two() called before it was defined
Big = 1024
};
constexpr int S::two() { return sz*2; }
constexpr S s;
int arr[s.two()]; // OK: s.two() called after its definition
struct complex
{
// constant-expression constructor
constexpr complex(double r, double i) : re(r), im(i) { } // OK: empty body
// constant-expression functions
constexpr double real() { return re; }
constexpr double imag() { return im; }
private:
double re;
double im;
};
constexpr complex COMP(0.0, 1.0); // creates a literal complex
double x = 1.0;
constexpr complex cx1(x, 0); // error: x is not a constant expression
const complex cx2(x, 1); // OK: runtime initialization
constexpr double xx = COMP.real(); // OK: compile-time initialization
constexpr double imaglval = COMP.imag(); // OK: compile-time initialization
complex cx3(2, 4.6); // OK: runtime initialization
cout << "Enter your age: ";
int age;
cin >> age;
const int myAge{age}; // works
constexpr int someAge{age}; // error: age can only be resolved at runtime
int main(int argc, char*argv[]) {
const int p = argc;
// p = 69; // cannot change p because it is a const
// constexpr int q = argc; // cannot be, bcoz argc cannot be computed at compile time
constexpr int r = 2^3; // this works!
// r = 42; // same as const too, it cannot be changed
}
const int x1=10;
constexpr int x2=10;
x1=20; // ERROR. Variable 'x1' can't be changed.
x2=20; // ERROR. Variable 'x2' can't be changed.
int temp=rand(); // temp is generated by the the random generator at runtime.
const int x1=10; // OK - known at compile time.
const int x2=temp; // OK - known only at runtime.
constexpr int x3=10; // OK - known at compile time.
constexpr int x4=temp; // ERROR. Compiler can't figure out the value of 'temp' variable at compile time so `constexpr` can't be applied here.
int temp=rand(); // temp is generated by the the random generator at runtime.
int array1[10]; // OK.
int array2[temp]; // ERROR.
const int size1=10; // OK - value known at compile time.
const int size2=temp; // OK - value known only at runtime.
constexpr int size3=10; // OK - value known at compile time.
int array3[size1]; // OK - size is known at compile time.
int array4[size2]; // ERROR - size is known only at runtime time.
int array5[size3]; // OK - size is known at compile time.
class test
{
int x;
void function1()
{
x=100; // OK.
}
void function2() const
{
x=100; // ERROR. The const methods can't change the values of object fields.
}
};
constexpr int func_constexpr(int X, int Y)
{
return(X*Y);
}
int func(int X, int Y)
{
return(X*Y);
}
int array1[func_constexpr(10,20)]; // OK - func_constexpr() can be evaluated at compile time.
int array2[func(10,20)]; // ERROR - func() is not a constexpr function.
int array3[func_constexpr(10,rand())]; // ERROR - even though func_constexpr() is the 'constexpr' function, the expression 'constexpr(10,rand())' can't be evaluated at compile time.
int value1=func_constexpr(10,rand()); // OK. value1 is non-constexpr value that is evaluated in runtime.
constexpr int value2=func_constexpr(10,rand()); // ERROR. value2 is constexpr and the expression func_constexpr(10,rand()) can't be evaluated at compile time.
class test2
{
static constexpr int function(int value)
{
return(value+1);
}
void f()
{
int x[function(10)];
}
};
class test3
{
public:
int value;
// constexpr const method - can't chanage the values of object fields and can be evaluated at compile time.
constexpr int getvalue() const
{
return(value);
}
constexpr test3(int Value)
: value(Value)
{
}
};
constexpr test3 x(100); // OK. Constructor is constexpr.
int array[x.getvalue()]; // OK. x.getvalue() is constexpr and can be evaluated at compile time.
#include<iostream>
constexpr int multiply (int x, int y)
{
return x * y;
}
extern const int val = multiply(10,10);
int main () {
std::cout << val;
}
val:
.long 100 //extra external definition supplied due to extern
main:
push rbp
mov rbp, rsp
mov esi, 100 //substituted in as an immediate
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
pop rbp
ret
__static_initialization_and_destruction_0(int, int):
.
.
.
#include<iostream>
const int multiply (int x, int y)
{
return x * y;
}
const int val = multiply(10,10); //constexpr is an error
int main () {
std::cout << val;
}
multiply(int, int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov eax, DWORD PTR [rbp-4]
imul eax, DWORD PTR [rbp-8]
pop rbp
ret
main:
push rbp
mov rbp, rsp
mov eax, DWORD PTR val[rip]
mov esi, eax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
pop rbp
ret
__static_initialization_and_destruction_0(int, int):
.
.
.
mov esi, 10
mov edi, 10
call multiply(int, int)
mov DWORD PTR val[rip], eax
const int x = 10;
int a[x] = {0};
constexpr auto x = 10;
struct Data { // We can make a bit field element of struct.
int a:x;
};
constexpr const int* p;
constexpr int square (int a){
return a*a;
}
constexpr int a = 3;
constexpr int b = 5;
int arr[square(a*b+20)] = {0}; //This expression is equal to int arr[35] = {0};
class Myclass {
const static int sx = 15; // OK
constexpr static int sy = 15; // OK
const static double sd = 1.5; // ERROR
constexpr static double sd = 1.5; // OK
};