A在以下程序中,在常量表达式中,创建了一个临时对象,并初始化了所有字段,然后函数在同一地址f创建了另一个对象A,跳过(重新)初始化字段x,随后读取该对象:
#include <memory>
struct A {
int x;
constexpr A() {}
constexpr A(int xx) : x(xx) {}
};
constexpr int f(A && a) {
std::construct_at<A>(&a);
return a.x;
}
static_assert( f(A{5}) == 5 ); //ok in GCC only
Run Code Online (Sandbox Code Playgroud)
GCC 接受得很好。但其他编译器会抱怨,例如 Clang:
note: read of uninitialized object is not allowed in a constant expression
return a.x;
^
Run Code Online (Sandbox Code Playgroud)
演示: https: //gcc.godbolt.org/z/87zrEb7q7
确实x没有在 中初始化std::construct_at<A>(&a),但它是在 中初始化的A{5}。
这里是哪个编译器?
我有以下代码在 c++20 中执行我想要的操作:
#include <iostream>
struct IntContainer
{
int value;
constexpr IntContainer(int init):value(init)
{
if(std::is_constant_evaluated())
{
value*=2;
}
else
{
std::cout<<"Constructed at runtime"<<std::endl;
}
}
};
int main()
{
constexpr int fixed=99;
int runtime;
std::cout<<"Enter runtime int value"<<std::endl;
std::cin>>runtime;
constexpr IntContainer fixed_container(fixed);
IntContainer runtime_container(runtime);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
对于fixed整数值,它默默地构造我的容器并将该值加倍,对于整runtime数值,它使用详细构造。该实现允许我声明fixed_container为constexpr.
我必须使用 c++20 才能使用该std::is_constant_evaluated功能,但我仅限于 c++17。是否有一些聪明的模板魔法我可以用来在没有此功能的情况下保持相同的行为?
如何使用参数(例如另一个元组)为类型列表中的每种类型调用模板函数?
给定的是一个类型列表std::tuple<T1, T2, T3, ...>和一个std::tuple包含数据。
template <typename T>
void doSomething (const auto& arg) {
std::cout << __PRETTY_FUNCTION__ << '\n';
}
template <typename T> struct w {T v; w(T _v) : v{_v} {}};
int main () {
using types = std::tuple<int, char, float, double, w<int>, w<float>>; // used as type list
constexpr auto data = std::make_tuple(1, 2, 3.0, 4.0f, w(5.0));
// call doSomething<T>(data) for each type in types
// like
// someFunctor<types>(doSomething, data);
}
Run Code Online (Sandbox Code Playgroud)
我当前的想法是一个类似函子的应用程序,它接收类型列表以提取下一个类型,并对每个 Tstd::tuple<Ts> …
经过两三天的尝试,我不得不放弃并编写了一个“最小”测试用例,希望能够证明该问题。
我需要的是一种将字符串文字(作为不带引号的宏参数传递)转换为可在 constexpr 环境中访问的字符串(用前缀连接)的方法(请参阅https://wandbox.org/permlink/Cr6j6fXemsQRycHI真实代码( tm));这意味着,它们(宏参数)应该被字符串化,然后转换为类型(例如 template <... 'h', 'e', 'l', 'l', 'o', ...>)或转换为static constexpr array<char, N>传递的唯一类型的 a (例如 template <... A<1> ...>,其中A<1>::strastatic constexpr array<char, 6>包含内容'h', 'e', 'l', 'l', 'o', '\0'.
我强烈喜欢后者,只有当后者不可能时才选择前者。
为了在简短的测试用例中演示确切的问题/要求,我提出了以下内容:
一些标题...
#include <array>
#include <tuple>
#include <cassert>
#include <string>
#include <iostream>
Run Code Online (Sandbox Code Playgroud)
然后为了演示最终结果应该如何表现:
template<int I>
struct A;
template<>
struct A<0>
{
static constexpr auto str = std::to_array("abc"); // The string-literal "abc" may NOT appear here.
// …Run Code Online (Sandbox Code Playgroud) 我有一个包装数组的类。它继承自一个抽象基类,virtual constexpr为函数调用运算符定义一种方法。在子类中,我重写所述方法并访问内部数组:
#include <cstddef>\n#include <array>\n#include <initializer_list>\n\ntemplate <typename T, std::size_t N>\nclass ContainerBase {\npublic:\n virtual constexpr const T& operator()(std::size_t i) const = 0;\n};\n\ntemplate <typename T, std::size_t N>\nclass Container : public ContainerBase<T, N> {\npublic:\n constexpr Container(std::initializer_list<T> data) {\n std::copy(data.begin(), data.end(), _items.begin());\n }\n constexpr const T& operator()(std::size_t i) const override {\n return _items[i];\n }\nprivate:\n std::array<T, N> _items;\n};\n\nint main () {\n constexpr Container<int, 3> C = {2, -91, 7};\n constexpr int F = C(1);\n\n static_assert(F == -91);\n}\nRun Code Online (Sandbox Code Playgroud)\n这是Godbolt 链接。 …
给定一个 constexpr 函数,是否有办法在编译时调用该函数时创建编译时错误,并在运行时调用该函数时返回哨兵值?
不幸的是,我无法使用异常,因为它们在构建中被禁用。
这主要用于与枚举之间的转换以及与字符串之间的转换。如果开发人员输入了不正确的值,最好让构建失败,而不是希望他们在运行时看到错误,但由于我们可以从未知来源获取值,因此该值有可能无效,我们不这样做不想在运行时崩溃。
演示用例:
#include <fmt/core.h>
#include <iostream>
// from: https://stackoverflow.com/a/63529662/4461980
// if C++20, we will need a <type_traits> include for std::is_constant_evaluated
#if __cplusplus >= 202002L
#include <type_traits>
#endif
constexpr bool is_constant_evaluated() {
#if __cplusplus >= 202002L
return std::is_constant_evaluated();
#elif defined(__GNUC__) // defined for both GCC and clang
return __builtin_is_constant_evaluated();
#else
// If the builtin is not available, return a pessimistic result.
// This way callers will implement everything in a constexpr way.
return true;
#endif
}
enum …Run Code Online (Sandbox Code Playgroud) 这个问题(和代码)的灵感来自 Jason Turner 的《C++ Weekly》一集:停止使用constexpr(并使用此代替!)
假设下面的代码(编译器资源管理器)
我的理解是,在声明函数局部变量时,static constexpr我保证该变量仅初始化一次(静态),并且如果编译器无法证明单线程访问(由于它是 constexpr),通常不需要任何线程安全开销。
但是c++标准能保证这一点吗?标准中是否有任何地方可以确保我该行static constexpr auto arr = getArr();永远不会导致编译器添加互斥体或其他类型的线程保护?
Jason Turner 的剧集或这个 stackoverflow 问题都没有提到局部静态变量可能带来的线程安全开销,这就是我正在寻找明确答案的要点 - 最好通过指向标准。
所以需要明确的是:我可以确保arr函数getVal()在编译时初始化,而不需要任何线程同步吗?
constexpr auto getArr()
{
std::array<int,10> arr;
for (int i = 0; i < 10; ++i) {
arr[i] = i*2;
}
return arr;
}
auto getVal(int i)
{
static constexpr auto arr = getArr();
return arr[i] + 1;
}
int main()
{
return …Run Code Online (Sandbox Code Playgroud) 不知何故,我仍然认为 lambda 是常规函数对象的“语法糖”,因此令我惊讶的是,在 C++-20 下,有状态但在其他方面的constexprlambda 实例不能用作非类型模板参数,这与等效的函数对象实例不同。
谁能解释这种行为或决定?
Godbolt示例:
struct always_fn {
const int x;
int operator()() const
{
return x;
}
};
inline constexpr always_fn always_f{5};
// lambda equivalent to `always_f`
inline constexpr auto always_2_f = [x = 5]() {
return x;
};
template<typename F>
struct wrapped {
F f_;
};
inline constexpr auto wrapped_f = wrapped{always_f};
inline constexpr auto wrapped_2_f = wrapped{always_2_f};
template<auto f>
void pass() {}
int main() {
pass<always_f>();
pass<wrapped_f>();
// error: no matching …Run Code Online (Sandbox Code Playgroud) 我有一个计算字符串文字的哈希值的函数:
inline consteval uint64_t HashLiteral(const char* key)
{
// body not important here...
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在另一个函数中,我需要文字字符串及其哈希值,我想在编译时计算它:
void function(const char* s)
{
worker(s, HashLiteral(s));
}
Run Code Online (Sandbox Code Playgroud)
然而,似乎不可能进行这样的调用function("string"),并在编译时在其主体中计算哈希值。我现在想到的最好方法是使用宏,并重新定义函数:
#define MakeHashParms(s) s,HashLiteral(s)
void function(const char* s, const uint64_t hash)
{
worker(s, hash);
}
function(MakeHashParms("string"));
Run Code Online (Sandbox Code Playgroud)
是否可以有更直接的解决方案?
我有这段代码:
template <int V>
struct Constant {
constexpr operator int() const noexcept { return V; }
};
template <class T, int N>
struct Array { };
auto function(auto s) -> Array<int, s + s> {
return {};
}
auto const a = function(Constant<3>{});
Run Code Online (Sandbox Code Playgroud)
让我最悲伤的是,似乎只有 Clang 接受这个代码。
哪个编译器是正确的,为什么?
c++ ×10
constexpr ×10
c++20 ×5
c++17 ×3
compiler-bug ×1
consteval ×1
lambda ×1
non-type-template-parameter ×1
templates ×1
tuples ×1
visual-c++ ×1