War*_* P 322 c++ constexpr c++11
在我看来,拥有"总是返回5的功能"正在破坏或淡化"调用函数"的含义.必须有一个原因,或者需要这种能力,或者它不会出现在C++ 11中.为什么会这样?
// preprocessor.
#define MEANING_OF_LIFE 42
// constants:
const int MeaningOfLife = 42;
// constexpr-function:
constexpr int MeaningOfLife () { return 42; }
Run Code Online (Sandbox Code Playgroud)
在我看来,如果我编写了一个返回字面值的函数,并且我进行了代码审查,有人会告诉我,我应该声明一个常量值而不是写回返5.
Goz*_*Goz 289
假设它做了一些更复杂的事情.
constexpr int MeaningOfLife ( int a, int b ) { return a * b; }
const int meaningOfLife = MeaningOfLife( 6, 7 );
Run Code Online (Sandbox Code Playgroud)
现在,您可以将某些内容评估为常量,同时保持良好的可读性,并允许稍微复杂的处理,而不仅仅是将常量设置为数字.
它基本上为可维护性提供了很好的帮助,因为它正在变得更加明显.就拿max( a, b )
例如:
template< typename Type > constexpr Type max( Type a, Type b ) { return a < b ? b : a; }
Run Code Online (Sandbox Code Playgroud)
它是一个非常简单的选择,但它确实意味着如果max
使用常量值调用它将在编译时显式计算,而不是在运行时.
另一个好例子是DegreesToRadians
功能.每个人都发现学位比弧度更容易阅读.虽然您可能知道180度是弧度,但更清楚地写如下:
const float oneeighty = DegreesToRadians( 180.0f );
Run Code Online (Sandbox Code Playgroud)
这里有很多好消息:
http://en.cppreference.com/w/cpp/language/constexpr
Fil*_*efp 139
constexpr
没有引入作为告诉实现的方法,可以在需要常量表达的上下文中评估某些内容; 符合实现已经能够在C++ 11之前证明这一点.
实现无法证明的是某段代码的意图:
constexpr
什么?假设您正在开发一个库并意识到您希望能够计算该区间中每个整数的总和(0,N]
.
int f (int n) {
return n > 0 ? n + f (n-1) : n;
}
Run Code Online (Sandbox Code Playgroud)
如果传递的参数在转换期间是已知的,编译器可以很容易地证明上述函数在常量表达式中是可调用的.但你没有宣称这是一个意图 - 事实恰恰相反.
现在别人出现,读取你的函数,做与编译器相同的分析; " 哦,这个函数可用于常量表达!" ,并编写以下代码.
T arr[f(10)]; // freakin' magic
Run Code Online (Sandbox Code Playgroud)
作为一个"令人敬畏"的库开发人员,您决定f
在调用时应该缓存结果; 谁想要一遍又一遍地计算同一组价值?
int func (int n) {
static std::map<int, int> _cached;
if (_cached.find (n) == _cached.end ())
_cached[n] = n > 0 ? n + func (n-1) : n;
return _cached[n];
}
Run Code Online (Sandbox Code Playgroud)
通过引入您的愚蠢优化,您只是打破了函数的每个用法,这些用法恰好位于需要常量表达式的上下文中.
你从来没有承诺该函数的是使用常数表达式,没有constexpr
就没有提供这样的承诺的方式.
constexpr
呢?constexpr的主要用途是声明意图.
如果实体未标记为constexpr
- 它从未打算用于常量表达式 ; 即使它是,我们依靠编译器来诊断这样的上下文(因为它忽略了我们的意图).
Kon*_*lph 91
拿std::numeric_limits<T>::max()
:无论出于何种原因,这是一种方法.constexpr
这将是有益的.
另一个例子:你想声明一个std::array
与另一个数组一样大的C数组(或a ).目前这样做的方法是这样的:
int x[10];
int y[sizeof x / sizeof x[0]];
Run Code Online (Sandbox Code Playgroud)
但是能写的不是更好:
int y[size_of(x)];
Run Code Online (Sandbox Code Playgroud)
谢谢你constexpr
,你可以:
template <typename T, size_t N>
constexpr size_t size_of(T (&)[N]) {
return N;
}
Run Code Online (Sandbox Code Playgroud)
def*_*ode 19
constexpr
函数非常好,是c ++的一个很好的补充.但是,你是对的,因为它解决的大多数问题都可以用宏来解决.
但是,其中一个用途constexpr
没有C++ 03等效的类型常量.
// This is bad for obvious reasons.
#define ONE 1;
// This works most of the time but isn't fully typed.
enum { TWO = 2 };
// This doesn't compile
enum { pi = 3.1415f };
// This is a file local lvalue masquerading as a global
// rvalue. It works most of the time. But May subtly break
// with static initialization order issues, eg pi = 0 for some files.
static const float pi = 3.1415f;
// This is a true constant rvalue
constexpr float pi = 3.1415f;
// Haven't you always wanted to do this?
// constexpr std::string awesome = "oh yeah!!!";
// UPDATE: sadly std::string lacks a constexpr ctor
struct A
{
static const int four = 4;
static const int five = 5;
constexpr int six = 6;
};
int main()
{
&A::four; // linker error
&A::six; // compiler error
// EXTREMELY subtle linker error
int i = rand()? A::four: A::five;
// It not safe use static const class variables with the ternary operator!
}
//Adding this to any cpp file would fix the linker error.
//int A::four;
//int A::six;
Run Code Online (Sandbox Code Playgroud)
小智 11
来自Stroustrup在"Going Native 2012"中的演讲:
template<int M, int K, int S> struct Unit { // a unit in the MKS system
enum { m=M, kg=K, s=S };
};
template<typename Unit> // a magnitude with a unit
struct Value {
double val; // the magnitude
explicit Value(double d) : val(d) {} // construct a Value from a double
};
using Speed = Value<Unit<1,0,-1>>; // meters/second type
using Acceleration = Value<Unit<1,0,-2>>; // meters/second/second type
using Second = Unit<0,0,1>; // unit: sec
using Second2 = Unit<0,0,2>; // unit: second*second
constexpr Value<Second> operator"" s(long double d)
// a f-p literal suffixed by ‘s’
{
return Value<Second> (d);
}
constexpr Value<Second2> operator"" s2(long double d)
// a f-p literal suffixed by ‘s2’
{
return Value<Second2> (d);
}
Speed sp1 = 100m/9.8s; // very fast for a human
Speed sp2 = 100m/9.8s2; // error (m/s2 is acceleration)
Speed sp3 = 100/9.8s; // error (speed is m/s and 100 has no unit)
Acceleration acc = sp1/0.5s; // too fast for a human
Run Code Online (Sandbox Code Playgroud)
另一个用途(尚未提及)是constexpr
构造函数.这允许创建编译时常量,这些常量不必在运行时初始化.
const std::complex<double> meaning_of_imagination(0, 42);
Run Code Online (Sandbox Code Playgroud)
与用户定义的文字配对,您完全支持文字用户定义的类.
3.14D + 42_i;
Run Code Online (Sandbox Code Playgroud)
曾经有一个元编程模式:
template<unsigned T>
struct Fact {
enum Enum {
VALUE = Fact<T-1>*T;
};
};
template<>
struct Fact<1u> {
enum Enum {
VALUE = 1;
};
};
// Fact<10>::VALUE is known be a compile-time constant
Run Code Online (Sandbox Code Playgroud)
我相信constexpr
是为了让你编写这样的结构而不需要模板和带有特化,SFINAE和东西的奇怪结构 - 但是就像你编写一个运行时函数一样,但保证结果将在编译中确定-时间.
但请注意:
int fact(unsigned n) {
if (n==1) return 1;
return fact(n-1)*n;
}
int main() {
return fact(10);
}
Run Code Online (Sandbox Code Playgroud)
编译它,g++ -O3
您将看到fact(10)
在编译时确实已经得到了证实!
一个支持VLA的编译器(所以C99模式下的C编译器或带有C99扩展的C++编译器)甚至可以允许你这样做:
int main() {
int tab[fact(10)];
int tab2[std::max(20,30)];
}
Run Code Online (Sandbox Code Playgroud)
但是目前它是非标准的C++ - constexpr
看起来像是一种解决这个问题的方法(即使没有VLA,在上面的例子中).并且仍然存在需要将"正式"常量表达式作为模板参数的问题.
刚刚开始将项目切换到c ++ 11并且遇到了constexpr的完美情况,它清理了执行相同操作的替代方法.这里的关键点是,只有在声明constexpr时,才能将函数放入数组大小声明中.在很多情况下,我可以看到这对我所涉及的代码区域非常有用.
constexpr size_t GetMaxIPV4StringLength()
{
return ( sizeof( "255.255.255.255" ) );
}
void SomeIPFunction()
{
char szIPAddress[ GetMaxIPV4StringLength() ];
SomeIPGetFunction( szIPAddress );
}
Run Code Online (Sandbox Code Playgroud)