我对一个constexpr概念感到困惑,因为我读过的constexpr是在编译时进行评估,因此它对于性能优化与正常情况相比非常有用const.
constexpr int i = 0;
constexpr int& ri = i;
Run Code Online (Sandbox Code Playgroud)
上面的代码返回一个错误"从'const int'类型的表达式中无效初始化类型'int&'的引用",为什么?
此外,下一个代码有一个错误:
constexpr int i = 0;
constexpr int* ri = &i;
Run Code Online (Sandbox Code Playgroud)
如果我替换了constexpr关键字const,以上所有都正常工作.
虽然我之前使用过这样的代码,但很明显编译器有足够的信息可以工作,但我真的不明白为什么这会编译:
template <class T, class I>
auto foo(const T& t, I i) {
return std::get<i>(t);
}
int main()
{
std::cerr << foo(std::make_tuple(3,4), std::integral_constant<std::size_t, 0>{});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
实例:http://coliru.stacked-crooked.com/a/fc9cc6b954912bc5.
似乎可以同时使用gcc和clang.的事情是,同时integral_constant具有constexpr转换所存储的整数,constexpr成员函数隐式地把对象本身作为参数,并且因此不能被用在这样的函数constexpr的上下文,除非我们正在呼叫的成员函数的对象本身可以作为被处理constexpr.
这里i是一个传递给的参数foo,因此i绝对不能被视为constexpr.然而,确实如此.一个更简单的例子:
template <class I>
void foo(I i) {
constexpr std::size_t j = i;
}
Run Code Online (Sandbox Code Playgroud)
这也是编译,只要std::integral_constant<std::size_t, 0>{}传递给foo.
我觉得我错过了一些关于constexpr规则的明显内容.无状态类型或其他类型是否有例外?(或者,也许是两个主要编译器中的编译器错误?这个代码似乎适用于clang 5和gcc 7.2).
编辑:答案已经发布,但我认为这还不够.特别是,鉴于最后的定义foo,为什么:
foo(std::integral_constant<std::size_t, …Run Code Online (Sandbox Code Playgroud) 我在玩autoin std::pair。在下面的代码中,函数f应该返回std::pair依赖于模板参数的类型。
一个工作示例:
例 1
template <unsigned S>
auto f()
{
if constexpr (S == 1)
return std::pair{1, 2}; // pair of ints
else if constexpr (S == 2)
return std::pair{1.0, 2.0}; // pair of doubles
else
return std::pair{0.0f, 0.0f}; // pair of floats
}
Run Code Online (Sandbox Code Playgroud)
这适用于 gcc 9.2、gcc 10.0、clang 9.0 和 clang 10.0。
接下来,std::pair为了清楚起见,我想明确地将返回类型写为 a :
例2
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return {1, …Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
#include <iostream>
class Test
{
public:
constexpr Test(const int x) : _x(x) {}
constexpr int get() const {return _x;}
~Test() {} // HERE
protected:
const int _x;
};
int main()
{
static constexpr Test test(5);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我删除该行HERE代码编译得很好,但是如果我定义一个空的析构函数,则会导致编译错误,说明Test它是非文字的.
为什么空的析构函数和没有析构函数之间有什么区别呢?
编辑:另一个相关的问题:如果空和文字析构函数不同如何定义受保护的文字析构函数?
由于标准的措辞,C++中的静态类成员给我带来了一点混乱:
9.4.2静态数据成员 [class.static.data]
在类定义中声明静态数据成员不是定义......
但是,constexpr需要在其声明中初始化(AFAIK,无法从标准中找到引用)(例如,在类定义中).
由于constexpr的限制,我实际上已经忘记了在类之外定义静态成员的必要条件,直到我尝试访问静态constexpr数组.这个相关问题提供了定义数组成员的正确方法,但我对类模板中对此定义的含义感兴趣.
这就是我最终得到的结果:
template<typename T>
class MyClass
{
private:
static constexpr std::size_t _lut[256] = { /* ... */ };
T _data;
public:
static constexpr std::size_t GetValue(std::size_t n) noexcept
{
return _lut[n & 255];
}
// ...
};
template<typename T>
constexpr std::size_t MyClass<T>::_lut[256];
Run Code Online (Sandbox Code Playgroud)
这是正确的语法吗?特别是在定义中使用模板感觉很尴尬,但GCC似乎正确地将所有内容联系起来.
作为后续问题,是否应该类似地定义非数组静态constexpr成员(模板定义在类外)?
我使用的是g ++ 4.8.0,它不包含早期的constexprbug.因此下面的代码工作正常:
constexpr int size() { return 5; }
int array[size()];
int main () {}
Run Code Online (Sandbox Code Playgroud)
但是,如果我将变量括在一个classas中static,那么它会给出编译器错误:
struct X {
constexpr static int size() { return 5; }
static const int array[size()];
};
int main () {}
Run Code Online (Sandbox Code Playgroud)
这是错误:
错误:数组'array'的大小不是整数常量表达式
禁止以constexpr这种方式使用还是使用另一个g ++ bug?
请考虑以下代码:
#include <stdio.h>
constexpr int f()
{
return printf("a side effect!\n");
}
int main()
{
char a[f()];
printf("%zd\n", sizeof a);
}
Run Code Online (Sandbox Code Playgroud)
我本来期望编译器抱怨printf内部的调用f,因为f应该是constexpr,但printf不是.为什么程序编译和打印15?
在C++ 11标准中,在标题中定义时constexpr,static constexpr全局变量之间有什么区别?更具体地说,当多个翻译单元包含相同的标题时,哪个声明(如果有的话)可以保证在翻译单元中定义相同的变量?
例如,
cexpr.h:
#ifndef CEXPR_H
#define CEXPR_H
constexpr int cint = 1;
static constexpr int scint = 1;
#endif
Run Code Online (Sandbox Code Playgroud)
a.cpp:
#include "cexpr.h"
Run Code Online (Sandbox Code Playgroud)
b.cpp:
#include "cexpr.h"
Run Code Online (Sandbox Code Playgroud) 对不起,这将是一个很长的帖子,但我觉得你需要所有的代码来看看发生了什么.
所以,我一直在尝试将编译时字符串转换为数据结构解析器.想象一下像正则表达式这样的东西,其中字符串在编译时被"编译"成数据结构但在运行时执行(只要输入字符串当然是常量).但是我遇到了一个我不太明白错误的问题:
基本上,我的设计是一个2遍解析器:
这是事情的样子:
// a class to wrap string constants
class constexpr_string {
public:
template <size_t N>
constexpr constexpr_string(const char (&s)[N]) : string_(s), size_(N - 1) {}
public:
constexpr size_t size() const { return size_; }
constexpr size_t capacity() const { return size(); }
constexpr size_t empty() const { return size() != 0; }
public:
constexpr char operator[](size_t n) const { return string_[n]; }
private:
const char *string_;
size_t size_;
};
// would have loved to …Run Code Online (Sandbox Code Playgroud) 我们的团队正在使用具有10多年历史的C ++代码库,并且最近切换到了C ++ 17编译器。因此,我们正在寻找使代码现代化的方法。在YouTube的一次会议演讲中,我听到了用替换const char*全局字符串的建议constexpr string_view。
由于我们的代码中有很多这样的const char*全局字符串常量,因此我想问一下是否需要了解一些陷阱或潜在问题?