如果我在常量表达式中除以零,我的玩具编译器会崩溃:
int x = 1 / 0;
Run Code Online (Sandbox Code Playgroud)
C和/或C++标准是否允许这种行为?
c c++ compile-time-constant divide-by-zero constant-expression
N4527 5.20 [expr.const] p5
常量表达式是glvalue核心常量表达式,其值指的是一个实体,它是常量表达式的允许结果(如下定义),或者是一个prvalue核心常量表达式,其值是一个对象,对于该对象及其子对象:
- 引用类型的每个非静态数据成员是指一个实体,它是一个常量表达式的允许结果,和
- 如果对象或子对象是指针类型,则它包含具有静态存储持续时间的对象的地址,超过此类对象的结尾的地址(5.7),函数的地址或空指针值.
如果实体是具有静态存储持续时间的对象,则该实体是常量表达式的允许结果,该对象不是临时对象,或者是其值满足上述约束的临时对象,或者它是函数.
void foo(){
int a = 1;
int b[a || 1]{};//ok in gcc 5.1.0, error in clang 3.8.0
static_assert(a || 1,"");//ok in gcc 5.1.0, error in clang 3.8.0
switch(1){
case a || 1://ok in gcc 5.1.0, error in clang 3.8.0
;
}
}
Run Code Online (Sandbox Code Playgroud)
是a || 1一个不变的表达?
N4527 5.20 [expr.const] p2
条件表达式e是核心常量表达式,除非根据抽象机器(1.9)的规则评估e将评估以下表达式之一:
(2.7) - 左值 - 右值转换(4.1),除非适用于
(2.7.1) - 整数或枚举类型的非易失性glvalue,它引用具有前面初始化的完整非易失性const对象,用常量表达式初始化,或者
(2.7.2) - 一个非易失性glvalue,引用字符串文字的子对象(2.13.5),或者
(2.7.3) - 一个非易失性glvalue,引用用constexpr定义的非易失性对象,或引用这种对象的不可变子对象,或者
(2.7.4) - …
以下程序编译:
template <const int * P>
class Test{};
extern const int var = 42; //extern needed to force external linkage
int main()
{
Test<&var> test;
}
Run Code Online (Sandbox Code Playgroud)
然而,这个没有,这对我来说是一个惊喜:
template <const int * P>
class Test{};
extern const int var = 42; //extern needed to force external linkage
extern const int * const ptr = &var; //extern needed to force external linkage
int main()
{
Test<ptr> test; //FAIL! Expected constant expression.
}
Run Code Online (Sandbox Code Playgroud)
替代示例:
int main()
{
const int size = 42;
int …Run Code Online (Sandbox Code Playgroud) 我有字符串常量,我在我的应用程序中的多个位置使用的字符串:
namespace Common{
static const std::string mystring = "IamAwesum";
}
Run Code Online (Sandbox Code Playgroud)
当发布关于其他内容的问题时(编译期间未包含在目标中的.h文件会发生什么?),另一位用户发表了以下评论:
请注意,在这种情况下,您的静态字符串是全局的.所以他们可以在任何时候创建一个例外,并且无法捕获.我建议你使用返回字符串引用的函数.std :: string const&mystring {static std :: string const mystring ="IamAwesum"; 通过这种方式返回mystring}你的对象只在需要时构造
有人可以解释为什么以我上面这样的方式使用静态const字符串,冒着抛出异常的风险吗?
请考虑以下代码段:
template <bool> struct B { };
template <typename T>
constexpr bool pred(T t) { return true; }
template <typename T>
auto f(T t) -> decltype(B<pred(t)>{})
{
}
Run Code Online (Sandbox Code Playgroud)
clang ++ (trunk)编译代码
g ++ (trunk)编译失败,出现以下错误:
src:7:34: error: template argument 1 is invalid
auto f(T t) -> decltype(B<pred(t)>{})
^
src:7:34: error: template argument 1 is invalid
src:7:34: error: template argument 1 is invalid
src:7:34: error: template argument 1 is invalid
src:7:34: error: template argument 1 is invalid
src:7:34: error: template …Run Code Online (Sandbox Code Playgroud)在针对C++ 11的SO上回答这个问题的过程中,我意识到在C++ 03(以及C)中,在常量表达式中明确禁止使用逗号运算符.
关于常量表达式的C++ 03标准的第5.19/1段说:
[...]特别是,除了sizeof表达式,不应使用函数,类对象,指针或引用,并且不得使用赋值,递增,递减,函数调用或逗号运算符.
但是,在C++ 11中,提到逗号运算符的最后一部分似乎已经消失了.虽然C++ 11标准的第5.19/2段明确规定赋值,递增,递减和非constexpr函数调用表达式不应作为常量表达式的子表达式出现,但逗号运算符的使用似乎不一致被禁止了.
例如,以下程序在GCC 4.7.2和Clang 3.3上编译良好std=c++11(除了编译器警告说逗号运算符没有效果且x和arr变量未使用):
int main()
{
constexpr int x = (0, 42);
int arr[(0, 42)];
}
Run Code Online (Sandbox Code Playgroud)
但是,必须要说的是,即使是以下程序也可以使用-std=c++03选项(在Clang和GCC上)编译好,这显然是不正确的,考虑到C++ 03标准的上述引用:
int main()
{
int arr[(0, 42)];
}
Run Code Online (Sandbox Code Playgroud)
题:
关于逗号运算符是否允许在常量表达式中,或者我是否遗漏了某些内容,C++ 03和C++ 11之间是否存在差异?
作为一个奖励(非建设性)问题,我有兴趣知道为什么逗号运算符不能用在C++ 03中的常量表达式中.
c++ comma-operator language-lawyer constant-expression c++11
我有以下代码:
class MyClass
{
static constexpr bool foo() { return true; }
void bar() noexcept(foo()) { }
};
Run Code Online (Sandbox Code Playgroud)
我希望,因为它foo()是一个static constexpr函数,并且因为它是在bar声明之前定义的,所以这是完全可以接受的.
但是,g++给我以下错误:
error: ‘static constexpr bool MyClass::foo()’ called in a constant expression
Run Code Online (Sandbox Code Playgroud)
这是......不太有用,因为在常量表达式中调用函数的能力是整个点constexpr.
clang++更有帮助.除了声明参数noexcept必须是常量表达式的错误消息之外,它还说:
note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
^
Run Code Online (Sandbox Code Playgroud)
那么......这是一个两遍编译问题吗?问题是编译器在定义任何成员函数之前是否尝试声明它们中的所有成员函数?(注意,在类的上下文之外,编译器都不会抛出错误.)这让我感到惊讶; 直观地说,我认为static constexpr成员函数不能在任何和所有常量表达式中使用,无论是在类中还是在类中.
据我所知,constC++中的限定符基本上声明了内部链接,有时它允许将变量用作常量表达式,以便将其放入数组边界、切换案例等。
但显然情况并非总是如此,我对const和的正确用法一无所知constexpr。
具体来说,我发现当在数组边界中使用 const 限定数组的元素时,它不会被视为常量表达式,如下面的代码所示。
const int N = 3;
int foo[N] = {1, 2, 3}; // Valid
const int bar[5] = {1, 2, 3, 4, 5};
int arr[bar[2]] = {1, 2, 3}; // Invalid because a VLA can't be initialized
Run Code Online (Sandbox Code Playgroud)
在后面的部分使用constexpr而不是const解决问题。但是为什么最后一条语句无效呢?究竟需要什么才能使表达式保持不变?
我知道三元运算符有一些令人惊讶的限制,但我有点困惑,这无法为我编译:
void foo(bool b)
{
int* ptr = ((b) ? NULL : NULL);
}
Run Code Online (Sandbox Code Playgroud)
显然,这是显示问题所需的最低限度.错误是:
[BCC32 Error] Unit11.cpp(20): E2034 Cannot convert 'int' to 'int *'
Run Code Online (Sandbox Code Playgroud)
编译器是不到100%符合Embarcadero C++ Builder 2010的,因此编译器错误远非不可能......
注意:修改Parens以避免混淆我的意图.
注2:我对自己如何首先得到这个结构感到有些困惑,所以这是我的借口:我在一行上得到了一些编译错误a = b? c : d,其中b,c和d都是复杂的表达式.为了缩小范围,我用s 代替c,以检查是否是罪魁祸首.在这一点上,一切都在手推车里下地狱.dNULLb
c++ conditional-operator null-pointer c++builder-2010 constant-expression
最近在回答问题时,我意识到只要表达式被包围,逗号运算符就被允许在C++ 11中的常量表达式中(),例如:
int a[ (1, 2) ] ;
Run Code Online (Sandbox Code Playgroud)
在C++ 11中,禁止在常量表达式中使用逗号运算符,来自草案预C++ 11标准部分5.19 常量表达式(强调我的):
[...]特别是,除了sizeof表达式,不应使用函数,类对象,指针或引用,并且不得使用赋值,递增,递减,函数调用或逗号运算符.
为什么逗号运算符不允许在C++ 11之前的常量表达式中,为什么解除了这个限制?