- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我检查了 GCC buglist和 Clang buglist并且还没有看到任何相关内容。
This Wandbox link显示一些 C++11/C++14 代码为各种类型的 x
执行 decltype(x)
和 decltype((x))
被 lambda 捕获。 GCC 和 Clang 对这段代码给出了不同的答案。如果有的话,哪一个是正确的?
这是有问题的片段:
// inside main()
int i = 42;
int &j = i;
[j=j](){
static_assert(std::is_same<decltype(j), GCC(const) int>::value,""); // A
static_assert(std::is_same<decltype((j)), const int&>::value,""); // B
}();
[=](){
static_assert(std::is_same<decltype(j), int&>::value,""); // C
static_assert(std::is_same<decltype((j)), CLANG(const) int&>::value,""); // D
}();
哪里:
#ifdef __clang__
#define CLANG(x) x
#define GCC(x)
#else
#define GCC(x) x
#define CLANG(x)
#endif
我相信在这两种情况下,实际捕获的东西(*) 是一个(非常量)int
初始化为 j 的拷贝
的值(也就是i
的值)。由于 lambda 未标记为 mutable
,因此其 operator()
将成为 const
成员函数。有了这些先决条件,让我们继续……
在线 //A
,GCC 告诉我显式初始化捕获的 j
的 decltype 是 const int
,当我'我几乎肯定它应该是 int
(根据 Clang)。
在 //B
行,两个编译器都同意 (j)
是一个引用 const int 的左值(因为 lambda 没有标记为 mutable
);这对我来说非常有意义。
在 //C
行,两个编译器都同意 j
是引用第 2 行声明的 int&
的名称。这是一个5.1.2 [expr.prim.lambda]/19 的结果,或者更确切地说,当那个子句不被调用时发生的事情的结果。在 [=]
lambda 中,name j
指的是外部作用域中的 j
,但是 < em>expression (j)
指的是 (j)
如果 j
被捕获,则该 (j)
将存在。我不完全理解它是如何工作的或者为什么它是可取的,但就是这样。我愿意声明这不是任何一个编译器中的错误。
在 //D
行,Clang 告诉我 (j)
是一个指代 const int 的左值,而 GCC 告诉我它是一个指代 a 的左值非常量 int。我很确定 Clang 是对的,而 GCC 是错的; decltype((j))
应该是相同的,无论 j
是隐式捕获还是显式捕获。
所以:
//A
和 //D
都是 GCC 中的错误吗?(*) — 事实上,第二个 lambda 在技术上没有捕获,因为它在任何评估的上下文中都没有使用 j
.这就是 //A
和 //C
行给出不同答案的原因。但是我不知道什么好用的术语来形容那件事-是-被完成-j
,所以我只是说“捕获”。
最佳答案
我相信
两个编译器对于 (A) 都是错误的,而 gcc 对于 (D) 是错误的。
我认为 gcc 对于 (A) 和 (D) 是错误的,而 clang 对于两者都是正确的。
[expr.lambda.prim] 的相关部分是:
An init-capture behaves as if it declares and explicitly captures a variable of the form “auto init-capture ;” whose declarative region is the lambda-expression’s compound-statement, except that:
— if the capture is by copy (see below), the non-static data member declared for the capture and the variable are treated as two different ways of referring to the same object, which has the lifetime of the non-static data member, and no additional copy and destruction is performed,
和
Every id-expression within the compound-statement of a lambda-expression that is an odr-use (3.2) of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type.
decltype(j)
不是 j
的 ODR 使用,因此不应考虑此类转换。因此,在 [=]{...}
的情况下,decltype(j)
应该产生 int&
。然而,在 init-capture 的情况下,行为就好像有一个 auto j = j;
形式的变量,而变量 j
引用相同的未命名非静态数据成员,无需进行此类转换。所以在 [j=j]{...}
的情况下,decltype(j)
应该产生该变量的类型 - 即 int
。它绝对不是 const int
。这是一个错误。
下一个相关部分:
Every occurrence of
decltype((x))
wherex
is a possibly parenthesized id-expression that names an entity of automatic storage duration is treated as ifx
were transformed into an access to a corresponding data member of the closure type that would have been declared ifx
were an odr-use of the denoted entity. [ Example:void f3() {
float x, &r = x;
[=] { // x and r are not captured (appearance in a decltype operand is not an odr-use)
decltype(x) y1; // y1 has type float
decltype((x)) y2 = y1; // y2 has type float const& because this lambda
// is not mutable and x is an lvalue
decltype(r) r1 = y1; // r1 has type float& (transformation not considered)
decltype((r)) r2 = y2; // r2 has type float const&
}
}—end example ]
该示例进一步说明了 decltype(j)
在隐式复制情况下应该是 int&
并且还演示了 decltype((j))
被视为好像 x
是将被声明的相应数据成员:在这两种情况下都是 int const&
(因为 lambda 不是 mutable
和 j
是一个左值)。您的 (C) 和 (D) 案例完全反射(reflect)了示例中的 r1
、r2
声明。其中,虽然示例不是规范的,但肯定表明 gcc 有不同的行为是错误的。
关于c++ - lambda : GCC bug and/or Clang bug? 中捕获变量的 decltype(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31040915/
由 this question 触发,我想知道是否允许这样做: template T foo(){return T{};} struct bar {}; int main() { bar a
我正在尝试以一种通用的方式实现 group_by 方法,我可能已经实现了它(除了它不适用于 C 数组),但代码对我来说仍然很难看...... 有没有更简单的方法来做我想做的事(+让它适用于所有容器和
这个问题在这里已经有了答案: What is decltype with two arguments? (2 个答案) 关闭 7 年前。 我遇到了一个decltype(),有两个参数作为模板函数的返
这是问题的后续:What does the void() in decltype(void()) mean exactly? . decltype(void()) 编译得很好,void() 在这种情况
这是我第一次使用decltype,我不太确定我是否正确使用它。该代码确实编译并且似乎适用于像 char 和 int 这样的 POD。 但是,我想知道我是否会遇到更复杂的数据类型的任何问题 - 其他人警
我一直在使用解析为与声明相同类型的定义中的推导返回类型。这有效: template struct Cls { static std::size_t f(); }; template declt
我发现它们是不同的,并且语言标准规定了每个语句应该检索什么样的类型(变量和表达式之间的差异)。但我真的很想知道为什么这两种类型应该不同? #include int x=0; decltype((x))
关于 decltype(x) 和 decltype((x)) 之间的区别,我已经读过很多遍了。一个例子如下。 x is the name of a variable, so decltype(x) i
我有一个简单的模板化包装器结构,其成员函数在其模板类型的对象上调用 .error()。 template struct Wrapper { T t; decltype(auto) f
decltype(auto) 和 decltype(returning expression) 作为函数(模板)的返回类型 if expr 有什么区别在这两种情况下都使用不带括号? auto f()
我在想 decltype((x)) 给出了 & 引用类型,但是一些实验表明还有其他事情: #include int main(){ int x = 0; decltype((x)) r
例如,简单的恒等仿函数: template class identity { public: constexpr auto operator ()(T && i) -> decltype(s
这个问题在这里已经有了答案: 关闭10 年前。 Possible Duplicate: decltype and parenthesis 我在维基百科上找到了这个: auto c = 0;
// g++ 7.3 template struct td; int main() { int a = 1; td t1; td t2; return 0; } 编译结果如下: 错误:
这确实是一个 C++14 问题。而且它的理论性多于实践性。 有时您会零碎地构建一个函数的结果: int f( int x, int y ) { int a; //... re
我试图检测成员函数 baz() 的存在在模板参数中: template struct ImplementsBaz : public std::false_type { }; template stru
考虑以下代码:(Ideone) struct S { int a() {return 0;} decltype(a()) b() {return 1;} }; 它给了我以下错误: er
(如果您是 C++11 专业人士,请跳至粗体段落。) 假设我想编写一个模板方法,该方法调用并返回传递的对象的结果,该对象的类型是模板参数: template ReturnType doSomethin
代码 #include int main() { int a=3; int *p=&a; decltype (a) k1; decltype (*p) k2;
我是 C++ 新手。我正在尝试学习 decltype 的概念。我在网上看到这段代码。我将 decltype(s1.size()) 更改为 int,代码工作正常。 decltype(s1.size())
我是一名优秀的程序员,十分优秀!