我想在类中定义一个常量,该值是最大可能的int.像这样的东西:
class A
{
...
static const int ERROR_VALUE = std::numeric_limits<int>::max();
...
}
Run Code Online (Sandbox Code Playgroud)
此声明无法使用以下消息进行编译:
numeric.cpp:8:错误:"的std :: numeric_limits :: MAX()"不能出现在一个常数表达式numeric.cpp:8:错误:一个函数调用不能出现在一个常数表达式
我理解为什么这不起作用,但有两件事对我来说很奇怪:
在我看来,在常量表达式中使用该值是一个自然的决定.为什么语言设计者决定使max()成为一个函数,从而不允许这种用法?
该规范在18.2.1中声称
对于在numeric_limits模板中声明为static const的所有成员,特化应以这样的方式定义这些值,使它们可用作整型常量表达式.
这不是说我应该能够在我的场景中使用它而不是它与错误信息相矛盾吗?
谢谢.
我试图声明一个constexpr指针初始化为一些常量整数值,但clang正在挫败我所有的尝试:
尝试1:
constexpr int* x = reinterpret_cast<int*>(0xFF);
test.cpp:1:20: note: reinterpret_cast is not allowed in a constant expression
Run Code Online (Sandbox Code Playgroud)
尝试2:
constexpr int* x = (int*)0xFF;
test.cpp:1:20: note: cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression
Run Code Online (Sandbox Code Playgroud)
尝试3:
constexpr int* x = (int*)0 + 0xFF;
test.cpp:1:28: note: cannot perform pointer arithmetic on null pointer
Run Code Online (Sandbox Code Playgroud)
是我试图不允许的设计?如果是这样,为什么?如果没有,我该怎么办?
注意:gcc接受所有这些.
下面的代码在clang ++ 3.7.0下编译,但被g ++ 5.3.1拒绝.两者都有-std=c++14选择权.哪个编译器正确?有谁知道标准在哪里谈论这个?谢谢.
#include <stdexcept>
using namespace std;
constexpr int f(int n) {
if (n <= 0) throw runtime_error("");
return 1;
}
int main() {
char k[f(1)];
}
Run Code Online (Sandbox Code Playgroud)
产量
[hidden] g++ -std=c++14 c.cpp
c.cpp: In function ‘constexpr int f(int)’:
c.cpp:7:1: error: expression ‘<throw-expression>’ is not a constant-expression
}
^
[hidden] clang++ -std=c++14 c.cpp
[hidden]
[hidden] g++ -v
Using built-in specs.
COLLECT_GCC=/usr/bin/g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/5.3.1/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release …Run Code Online (Sandbox Code Playgroud) (据我所知,使用的编译器是带有 c++17 的 gcc(在 Visual Studio 中很难找到))
#include <iostream>
using namespace std;
void increment( int& v )
{
++v;
}
int constexpr f()
{
int v = 0;
increment( v );
return v;
}
int main( )
{
cout << f( ) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
上面的代码给出了编译错误:
constexpr 函数 'f' 不能产生常量表达式。
据我了解,这是因为该函数increment不是 constexpr。让我困惑的是以下代码编译得很好:
#include <iostream>
using namespace std;
void increment( int& v )
{
++v;
}
int constexpr f()
{
int v = 0;
for( int i = 0; …Run Code Online (Sandbox Code Playgroud) 使用新的C++ 11标准,何时应该在inline关键字上使用constexpr关键字?constexpr关键字是否提供任何额外的优化inline,或仅仅断言必须在编译时计算事物?
为什么constexpr在调用不稳定的某些情况下在GCC 上工作,例如调用foo(x)非constexpr变量?这是GCC中的错误还是它实际上是标准的一部分?
我想在编译时使用类型的名称.例如,假设我写了:
constexpr size_t my_strlen(const char* s)
{
const char* cp = s;
while(*cp != '\0') { cp++; };
return cp - s;
}
Run Code Online (Sandbox Code Playgroud)
现在我希望:
template <typename T>
constexpr auto type_name_length = my_strlen(typeid(T).name());
Run Code Online (Sandbox Code Playgroud)
但是,唉,typeid(T).name()只是const char*,而不是constexpr ......还有其他一些constexpr方法来获得一个类型的名字吗?
我有以下帮助函数:
template<typename T, std::size_t N>
constexpr std::size_t Length(const T(&)[N]) {
return N;
}
Run Code Online (Sandbox Code Playgroud)
返回静态数组的长度.在过去,这总是有效,但当我这样做时:
struct Foo
{
unsigned int temp1[3];
void Bar()
{
constexpr std::size_t t = Length(temp1); // Error here
}
};
Run Code Online (Sandbox Code Playgroud)
使用MSVS 2017时出错:
Run Code Online (Sandbox Code Playgroud)error C2131: expression did not evaluate to a constant note: failure was caused by a read of a variable outside its lifetime note: see usage of 'this'
我希望有人能说清楚我做错了什么.
我无法理解为什么gcc-8.2.0和clang-7.0.0都拒绝以下代码(这里的实时代码):
#include <array>
int main() {
constexpr std::array<int,3> v{1,2,3};
constexpr auto b = v.begin(); // error: not a constexpr
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有错误
error: '(std::array<int, 3>::const_pointer)(& v.std::array<int,3>::_M_elems)'
is not a constant expression (constexpr auto b = v.begin();)
Run Code Online (Sandbox Code Playgroud)
根据en.cppreference.com,begin()声明了成员函数constexpr.这是编译器错误吗?
实际上,如果值类型为TriviallyCopyable,则std :: copy的实现应避免多次分配,并使用大容量复制功能,例如std :: memmove
但是,该页面还指出,不采用执行策略的重载将constexpr自C ++ 20开始。该标准是否会禁止这些运行时优化(因为std::memmove不是constexpr),或者是否有一种方法可以优化constexpr运行时的功能?
鉴于源代码中唯一不同的两个程序是否存在constexpr,程序的含义是否可能发生变化?
换句话说,如果有一个编译器选项要求编译器尝试很难推断constexpr可能的地方,它会破坏现有的标准代码和/或以不好的方式改变其含义吗?
想象一下处理一个代码库,原始开发人员忘记将其包含constexpr在可能的地方,也许是在C++ 11之前编写的代码.如果编译器推断constexpr可以帮助您继续工作,那将会很棒.当然,或许它也应该在每次进行推理时发出警告,鼓励你明确添加constexpr后者.但它仍然有用.我担心它会破坏东西吗?
到目前为止,我唯一能想到的是constexpr函数是隐含的,inline并且可能存在添加inline可能以不良方式改变事物的情况; 例如,如果您违反了单定义规则.
c++ ×10
constexpr ×10
c++11 ×3
c++14 ×2
c++17 ×2
optimization ×2
c++20 ×1
clang ×1
compile-time ×1
gcc ×1
inline ×1
pointers ×1
reflection ×1
std ×1
templates ×1