是否有可能根据C++ 11中的C++ 11表达式是否为常量表达式(即constexpr)生成编译时布尔值?关于SO的几个问题与此有关,但我在任何地方都没有看到直接答案.
让我说我有
std::tuple<T0, T1, T2> my_tuple{x0, x1, x2};
Run Code Online (Sandbox Code Playgroud)
其中T0,T1和T2是值类型(即没有混叠是可能的).
只要每个线程访问不同的元素,访问my_tuple元素并从多个线程同时改变它们是否安全std::get?
例:
template <typename T>
void process(T& x) { /* mutate `x` */ }
// ...
std::thread{[&]{ process(std::get<0>(my_tuple)); }}.detach();
std::thread{[&]{ process(std::get<1>(my_tuple)); }}.detach();
std::thread{[&]{ process(std::get<2>(my_tuple)); }}.detach();
Run Code Online (Sandbox Code Playgroud)
本能地,我会说它是安全的,my_tuple可以被认为是struct { T0 x0; T1 x1; T2 x2; };......但它是否由标准保证?
几天前,我询问编译器决定是否在编译期间计算constexpr函数.
事实证明,只有在编译时才会评估constexpr,如果所有参数都是常量表达式,并且您指定给它的变量也是常量表达式.
template<typename base_t, typename expo_t>
constexpr base_t POW(base_t base, expo_t expo)
{
return (expo != 0 )? base * POW(base, expo -1) : 1;
}
template<typename T>
void foobar(T val)
{
std::cout << val << std::endl;
}
int main(int argc, char** argv)
{
foobar(POW((unsigned long long)2, 63));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我被告知是真的,这个代码示例是非常不实际的,因为foobar不接受constexpr(由于某种原因你不能使用consexpr作为参数),POW在运行时被评估,即使它可能是可能的在编译期间计算它.强制编译时评估的明显解决方案是:
auto expr = POW((unsigned long long)2, 63);
foobar(expr);
Run Code Online (Sandbox Code Playgroud)
然而,这迫使我使用额外的代码行,每次我想确保在编译时评估constexpr时都不需要这样做.为了使这更方便一点,我想出了以下可疑的宏:
#define FORCE_CT_EVAL(func) [](){constexpr auto ___expr = func; return std::move(___expr);}()
foobar(FORCE_CT_EVAL(POW((unsigned long long)2, 63)));
Run Code Online (Sandbox Code Playgroud)
尽管它工作得很好,但我觉得好像有些不对劲.创建匿名lambda会影响性能吗?通过rvalue引用返回实际上是将表达式移动到函数参数吗?std :: move如何影响性能?有没有更好的单线解决方案呢?
我已经定义了一个constexpr函数如下:
constexpr int foo(int i)
{
return i*2;
}
Run Code Online (Sandbox Code Playgroud)
这就是主要功能:
int main()
{
int i = 2;
cout << foo(i) << endl;
int arr[foo(i)];
for (int j = 0; j < foo(i); j++)
arr[j] = j;
for (int j = 0; j < foo(i); j++)
cout << arr[j] << " ";
cout << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该程序是在OS X 10.8下用命令clang ++编译的.我很惊讶编译器没有产生关于foo(i)不是常量表达式的任何错误消息,并且编译的程序实际上工作正常.为什么?
我有什么保证可能包含 constexpr 函数调用的核心常量表达式(如在 [expr.const].2 中)将在编译时实际评估,这取决于哪些条件?
constexpr通过将计算移至翻译阶段(编译时),引入隐式承诺提高运行时性能。这两点似乎相互矛盾。
在什么情况下可以依靠编译器在编译时解析核心常量表达式(可能包含任意复杂的计算)而不是将其推迟到运行时?
至少在-O0gcc下似乎实际上发出代码并调用 constexpr 函数。在-O1最多不。
难道我们不得不求助于挂羊头卖狗肉,如这个,那个力量通过模板系统constexpr:
template <auto V>
struct compile_time_h { static constexpr auto value = V; };
template <auto V>
inline constexpr auto compile_time = compile_time_h<V>::value;
constexpr int f(int x) { return x; }
int main() {
for (int x = 0; x < compile_time<f(42)>; ++x) {}
}
Run Code Online (Sandbox Code Playgroud) @cyberpunk_试图实现一些目标,并提出了一些问题,但所有的追逐都归结为:
是否可以构建一个工具来强制执行constexpr函数的编译时评估?
int f(int i) {return i;}
constexpr int g(int i) {return i;}
int main()
{
f(at_compilation(g, 0));
int x = at_compilation(g, 1);
constexpr int y = at_compilation(g, 2);
}
Run Code Online (Sandbox Code Playgroud)
在所有情况下,at_compilation强制执行g.
at_compilation不需要采用这种形式。
所有代码示例都有关于要求的限制。
清楚地解释这在 C++ 中如何不可行也是一个很好的答案。
我怀疑这是不可能的,基于@K-ballo / @Herb Sutter 的 回答 …
我们刚开始在C++ 11中学习模板元编程.作为练习,我们编写了一个程序,输出int值的二进制表示.我们想出了两个可能的实现.第一个使用带有枚举值的递归,而第二个方法使用constexpr函数.
我们的期望是两个实现都会产生相同大小的可执行文件.但是,第一个实现导致9064字节,而第二个实现9096字节.我们不介意字节上的微小差异,但不明白导致差异的原因.
我们使用GCC 4.8.2编译了没有优化标志的程序,但是,找到了相同的结果-O2标志.
#include <iostream>
using namespace std;
template <int val>
struct Bin
{
enum { value = 10 * Bin<(val >> 1)>::value + (val & 1) };
};
template <>
struct Bin<0>
{
enum { value = 0 };
};
constexpr int bin(int val)
{
return val == 0 ? 0 : (10 * bin(val >> 1) + (val & 1));
}
int main()
{
// Option 1
cout << Bin<5>::value << '\n'
<< Bin<27>::value << '\n'; …Run Code Online (Sandbox Code Playgroud) 为什么C ++编译器可以将函数声明为constexpr,而不能将其声明为constexpr?
例如:http : //melpon.org/wandbox/permlink/AGwniRNRbfmXfj8r
#include <iostream>
#include <functional>
#include <numeric>
#include <initializer_list>
template<typename Functor, typename T, size_t N>
T constexpr reduce(Functor f, T(&arr)[N]) {
return std::accumulate(std::next(std::begin(arr)), std::end(arr), *(std::begin(arr)), f);
}
template<typename Functor, typename T>
T constexpr reduce(Functor f, std::initializer_list<T> il) {
return std::accumulate(std::next(il.begin()), il.end(), *(il.begin()), f);
}
template<typename Functor, typename T, typename... Ts>
T constexpr reduce(Functor f, T t1, Ts... ts) {
return f(t1, reduce(f, std::initializer_list<T>({ts...})));
}
int constexpr constexpr_func() { return 2; }
template<int value>
void print_constexpr() …Run Code Online (Sandbox Code Playgroud) 说你有一个像这样的功能:
double do_it(int m)
{
double result = 0;
for(int i = 0; i < m; i++)
result += i;
return result;
}
Run Code Online (Sandbox Code Playgroud)
如果您在编译时知道m,则可以执行以下操作:
template<size_t t_m>
double do_it()
{
double result = 0;
for(int i = 0; i < t_m; i++)
result += i;
return result;
}
Run Code Online (Sandbox Code Playgroud)
在优化时,这为诸如循环展开之类的事情提供了可能性。但是,有时您可能在编译时知道一些情况,而在运行时知道一些情况。或者,也许您有可以由用户更改的默认值...但是优化默认情况会很好。
我想知道是否有任何方法可以提供两个版本而基本上不复制代码或使用宏?
注意,以上是说明这一点的玩具示例。
我constexpr用来获得斐波纳契数
枚举用于在编译时计算斐波那契数
#include <iostream>
constexpr long fibonacci(long long n)
{
return n < 1 ? -1 :
(n == 1 || n == 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2));
}
enum Fibonacci
{
Ninth = fibonacci(9),
Tenth = fibonacci(10),
Thirtytwo = fibonacci(32)
};
int main()
{
std::cout << Fibonacci(Thirtytwo);
// std::cout << fibonacci(32);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我在执行时遇到以下错误:
1>c:\users\hsingh\documents\visual studio 2017\projects\consoleapplication4\consoleapplication4\source.cpp(12): note: while evaluating 'fibonacci(30)' 1>c:\users\hsingh\documents\visual studio 2017\projects\consoleapplication4\consoleapplication4\source.cpp(6): note: while evaluating 'fibonacci(31)' …
我知道ISO C标准在分离翻译行为和执行行为方面做了大量工作,部分原因是为了确保交叉编译器不必承载每个目标的执行环境.
这就是说,与正在运行的程序相比,编译器可用的信息有限.这限制了您可以在源代码中执行的操作,例如不基于此函数的返回值初始化变量:
int twice (int val) { return val * 2; }
int xyzzy = twice (7);
int main () { printf ("%d\n", xyzzy); return 0; }
Run Code Online (Sandbox Code Playgroud)
我很好奇的是C++ 11中用户定义的文字如何适合这个方案.由于文字评估依赖于一个函数,所以要阻止该函数执行以下操作:
42_roughly给出40到44之间的值)?是否必须调用函数意味着在编译时计算这些函数并不是真正的文字吗?
如果是这样的话,这些文字比任何其他函数调用的优点是什么.换句话说,为什么:
int xyzzy = 1101_1110_b;
Run Code Online (Sandbox Code Playgroud)
优选:
int xyzzy = makeBin ("1101_1110");
Run Code Online (Sandbox Code Playgroud)
?
c++ ×11
c++11 ×8
constexpr ×7
compile-time ×3
c++20 ×1
compilation ×1
evaluation ×1
function ×1
macros ×1
stdtuple ×1
templates ×1