我有一小段代码可以在clang repo head(3.5)中编译好,但在gcc 4.9 repo head中没有 . 虽然这看起来像一个gcc bug,但在发送bugzilla之前我想问你是否
-
这是有效的c 1y代码(在当前的草稿状态中) - 只是因为clang编译它没有理由使它成为正确的代码,并且
-
如果有人可以重现这个bug .
使用clang编译和运行的代码片段在这里:
http://coliru.stacked-crooked.com/a/acc691b9a407d6f2
然而使用
g++-4.9 -o main main.cpp -std=c++1y
给我上面提到的内部编译器错误:http://pastebin.com/3fqV7xzC
如果没有长转储,它会显示:
g -4.9 -o main main.cpp -std = c 1y main.cpp:在'composer :: operator()的实例化中(Func &&,Funcs && ...):: [with auto:2 = float; Func = main(int,const char *)::; Funcs = {main(int,const char *)::}]':main.cpp:33:88:从这里需要
main.cpp:19:41: internal compiler error: in retrieve_specialization, at cp/pt.c:1042
return f(c(std::forward<Funcs>(fs)...)(v));
^
为了完整性,这里是片段(完整的main.cpp)
#include <iostream>
#include <utility>
template <typename... Funcs>
struct composer;
template <>
struct composer<> {
auto operator()() {
return [&] (auto v) { return v; };
}
};
template <typename Func, typename... Funcs>
struct composer<Func, Funcs...> {
auto operator()(Func&& f, Funcs&&... fs) {
composer<Funcs...> c;
return [&] (auto v) {
return f(c(std::forward<Funcs>(fs)...)(v));
};
}
};
template <typename... Funcs>
auto compose(Funcs&&... fs) {
composer<Funcs...> c;
return c(std::forward<Funcs>(fs)...);
}
int main (int argc, char const* argv[]) {
float v = 3.5f;
auto t = compose([] (auto v) { return v >= 3; }, [] (auto v) { return int(v-0.5); })(v);
std::cout << std::boolalpha << t << "\n";
auto f = compose([] (auto v) { return v > 3; }, [] (auto v) { return int(v-0.5); })(v);
std::cout << std::boolalpha << f << "\n";
}
Edit: 奖金!我没有't like that code at all - if anyone'有一个更好的,可能更快的方式来做这个考虑启发我...
Edit 2 有谁知道怎么让coliru(或类似的服务)使用g 4.9?
1 回答
您的代码无效C 1y,至少在执行时没有 .
您通过引用捕获变量,然后退出定义它们的范围,然后调用使用所述变量的lambda .
现在,
c
的状态从未使用过,但operator()
调用仍然是UB .同样,虽然您的引用是与当前范围相比的数据,但不能保证捕获原始变量而不是本地引用 . 实现本地捕获的一种方法是捕获指向本地堆栈帧的指针,并通过来自所述堆栈帧的编译时静态偏移来访问变量:当您退出堆栈帧时,这样的读取将生成垃圾 . (这会将
[&]
lambda的大小减小到单个指针,这是一个非常好的优化!在某些机器上,通过指针偏移访问数据的速度很快 . )一般而言,如果您的闭包(或其副本)将超过当前范围,则不要通过引用(尤其是通过全局引用)捕获 .
return
语句上的全局引用捕获应该会生成警告 .修复UB和您的代码看起来有效 . 在C 1y中,您可以捕获
move
或 -forward
.没有C 1y编译器,这里有一个刺:
这也恰好是非lambda类型 .