这是有效的,因为一个constexpr表达式被允许取的值"文字类型的glvalue其指的是与constexpr定义的非挥发性物体,或者是指这样的对象的一个子对象"(§5.19/ 2 ):
constexpr char str[] = "hello, world";
constexpr char e = str[1];
Run Code Online (Sandbox Code Playgroud)
但是,似乎字符串文字不符合此描述:
constexpr char e = "hello, world"[1]; // error: literal is not constexpr
Run Code Online (Sandbox Code Playgroud)
2.14.5/8描述了字符串文字的类型:
普通字符串文字和UTF-8字符串文字也称为窄字符串文字.窄字符串文字具有类型"n const char数组",其中n是下面定义的字符串的大小,并且具有静态存储持续时间.
看起来这种类型的对象可以被索引,只要它是临时的而不是静态存储持续时间(5.19/2,就在上面的代码片段之后):
[
constexpr允许lvalue-to-rvalue转换] ...一个文字类型的glvalue,引用一个非易失性临时对象,其生命周期尚未结束,用一个常量表达式初始化
这是特别奇怪的,因为取一个临时对象的左值通常是"作弊".我想这个规则适用于引用类型的函数参数,例如in
constexpr char get_1( char const (&str)[ 6 ] )
{ return str[ 1 ]; }
constexpr char i = get_1( { 'y', 'i', 'k', 'e', 's', '\0' } ); // OK
constexpr char e = get_1( "hello" ); // error: string …Run Code Online (Sandbox Code Playgroud) 在C++中声明和定义全局常量的最佳方法是什么?我最感兴趣的是C++ 11标准,因为它在这方面做了很多修复.
[编辑(澄清)]:在这个问题中,"全局常量"表示在编译时在任何范围内已知的常量变量或函数.必须可以从多个翻译单元访问全局常量.它不一定是constexpr风格不变-可以是这样const std::map<int, std::string> m = { { 1, "U" }, { 5, "V" } };或const std::map<int, std::string> * mAddr() { return & m; }.在这个问题中,我没有触及优选的好的范围或常数名称.让我们把这些问题留给另一个问题.[END_EDIT]
我想知道所有不同情况的答案,所以让我们假设这T是以下之一:
typedef int T; // 1
typedef long double T; // 2
typedef std::array<char, 1> T; // 3
typedef std::array<long, 1000> T; // 4
typedef std::string T; // 5
typedef QString T; // 6
class T {
// unspecified amount of code
}; // 7
// …Run Code Online (Sandbox Code Playgroud) 据我所知(至少对于c++14),如果析构函数constexpr不是微不足道的(隐式生成或=default),则析构函数不可能.constexpr为具有非平凡析构函数的结构声明构造函数有什么意义?
struct X {
int a_;
constexpr X(int a) : a_{a} {}
// constexpr ~X(){}; // Error dtor cannot be marked constexpr
// ~X(){}; // causes error at y declaration: temporary of non-literal type ‘X’
// in a constant expression .
};
template <int N> struct Y {};
int main() {
Y<X{3}.a_> y; // OK only if the destructor is trivial
(void)y;
}
// tested with c++14 g++-5.1.0 and clang++ 3.5.0
Run Code Online (Sandbox Code Playgroud)
例如 …
为什么这个constexpr static由//! Nah注释标识的成员函数constexpr在调用时看不到?
struct Item_id
{
enum Enum
{
size, position, attributes, window_rect, max_window_size, _
};
static constexpr int n_items_ = _; // OK
constexpr auto member_n_items() const -> int { return _; } // OK
static constexpr auto static_n_items() -> int { return _; } // OK
static constexpr int so_far = n_items_; // OK
#ifndef OUT_OF_CLASS
static constexpr int bah = static_n_items(); //! Nah.
#endif
};
constexpr auto n_ids() -> int { …Run Code Online (Sandbox Code Playgroud) 考虑以下代码:
#include <vector>
struct A {
static constexpr int kDefaultValue = -1;
std::vector<int> v;
A(int n): v(n, A::kDefaultValue) {}
};
int main() {
A(10);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它无法链接(llvm clang,gcc 4.9,两者都在OS X上):
Undefined symbols for architecture x86_64:
"A::kDefaultValue", referenced from:
A::(int) in main.cpp.o
ld: symbol(s) not found for architecture x86_64
Run Code Online (Sandbox Code Playgroud)
问题是它有什么问题?它可以通过static_cast-ing A::kDefaultValue来修复int.或者搬出kDefaultValue去A.两个案件似乎都很难看.这是另一种使它链接的方式吗?
我对一个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) 我有这个代码,如果你注释掉行注释" 但这不起作用?! "它编译得很好,但如果你没有,编译器会产生错误.
至少,gcc 8.2会产生错误.
但是,它们似乎与我相同.有什么问题?这是合法代码吗?
template <int x>
struct test_template {
static int size() { return x; }
};
constexpr int ce_strlen(char const *s)
{
int i = 0;
while (s[i]) ++i;
return i;
}
int joe()
{
constexpr int plen = ce_strlen(__PRETTY_FUNCTION__); // This works
test_template<plen> a; // This declaration is valid.
test_template<ce_strlen(__PRETTY_FUNCTION__)> b; // But this doesn't work?!
return a.size() + b.size();
}
Run Code Online (Sandbox Code Playgroud)
我试图想出一种在编译时为侵入性分析系统创建配置文件标签的方法.我成功了,但我的最终代码不涉及使用ce_strlen.
template<class A, class B> constexpr int f(A a, B b) {
a /= b;
return a;
}
constexpr int x = f(2, 2); // a, b: int
constexpr int y = f(2., 2.); // a, b: double
constexpr int z = f(2, 2.); // a: int, b: double //<-- BOOM!
constexpr int w = f(2., 2); // a: double, b: int
int main() {}
Run Code Online (Sandbox Code Playgroud)
代码不在clang中编译,它产生以下诊断:
error: constexpr variable 'z' must be initialized by a constant expression
Run Code Online (Sandbox Code Playgroud)
MSVC坠毁(根据godbolt)并且gcc工作正常.如果a …
我在玩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)