gpt4 book ai didi

c++ - lambda 中值捕获的 std::move() 上的 decltype() 导致类型不正确

转载 作者:行者123 更新时间:2023-12-01 13:09:09 24 4
gpt4 key购买 nike

似乎 Clang (9.0.0) 或我对 decltype() 的理解有问题被指定在标准中工作。引用以下代码,

#include <utility>
#include <string>

template <typename...> class WhichType;

template <typename T>
std::remove_reference_t<T>&& move_v2(T&& t) {
WhichType<std::remove_reference_t<T>&&>{};
return static_cast<std::remove_reference_t<T>&&>(t);
}

int main() {
auto x = std::string{"a"};
[v = x]() {
// move_v2(v);
// WhichType<decltype(move_v2(v))>{};
WhichType<decltype(std::move(v))>{};
}();
}

上面的代码有编译器输出 implicit instantiation of undefined template 'WhichType<std::__1::basic_string<char> &&>'而不是预期的 const std::__1::basic_string<char> &&WhichType的模板参数中.使用 move_v2WhichTypemove_v2虽然它本身似乎输出了正确的东西。

但是,Clang 似乎也对 std::move(v) 做了重载解析。如我所料 https://wandbox.org/permlink/Nv7yXnCbqxjJMVvX .这让我的一些顾虑烟消云散,但我还是不明白 decltype() 的行为在 lambda 内部。

在这种特殊情况下,GCC 似乎没有这种不一致 https://wandbox.org/permlink/5mhrOzLn5XZO8LNB .

如果我对 decltype() 的理解有误,有人可以纠正我吗?或者指出这个错误在 clang 中出现的确切位置?乍一看似乎有点吓人。在 SFINAE 或类似的东西中使用时,这可能会导致问题。

最佳答案

我已经做了一些挖掘,在我看来,答案比某些评论看起来更微妙。

首先是this answer to an earlier question .引用重要部分:

[C++11: 5.1.2/14]: An entity is captured by copy if it is implicitly captured and the capture-default is = or if it is explicitly captured with a capture that does not include an &. For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The declaration order of these members is unspecified. The type of such a data member is the type of the corresponding captured entity if the entity is not a reference to an object, or the referenced type otherwise. [..]



然后是 this answer to another question .再次引用:

5 The closure type for a non-generic lambda-expression has a public inline function call operator [...] This function call operator or operator template is declared const (9.3.1) if and only if the lambda-expression’s parameter-declaration-clause is not followed by mutable.



然后我把它放在一个小测试中:
#include <iostream>
using std::cout;
using std::endl;

void foo(const std::string&) {
cout << "void foo(const std::string&)" << endl;
}

void foo(std::string&) {
cout << "void (std::string&)" << endl;
}

struct klaf
{
std::string b;

void bla() const
{
cout << std::boolalpha << std::is_const<decltype(b)>::value << endl;
foo(b);
}
};

int main()
{
klaf k;
k.bla();

std::string s;
const std::string s2;
auto lam = [=]() {
cout << std::boolalpha << std::is_const<decltype(s)>::value << endl;
foo(s);

cout << std::boolalpha << std::is_const<decltype(s2)>::value << endl;
foo(s2);
};
lam();
}

哪些输出(以及 GCC、Clang 和 MSVC 中的输出相同):
false
void foo(const std::string&)
false
void foo(const std::string&)
true
void foo(const std::string&)
klaf::b是(显然)不是 const ,但由于 klaf::bla功能是 const ,然后 klaf::b被视为 const在调用 foo .

lam中也是如此哪里 s被类型为 std::string 的值捕获.然而, s2已声明为 const std::string并延续到 lambda 中数据成员的类型。

简而言之:在 lambda 中按值捕获不会使捕获的成员本身 const ,但由于 operator()对于 lambda 是 const ,则成员被提升为 const在该函数中(除非 lambda 被声明为可变的)。

编辑:

受到@arnes 评论的启发,我发现 GCC 和 Clang 有所不同:
int main()
{
int i = 12;
auto lam = [=, ic = i]() {
cout << std::boolalpha << std::is_const<decltype(i)>::value << endl;
cout << std::boolalpha << std::is_const<decltype(ic)>::value << endl;
};
lam();
}

这会产生 false false在 Clang,但是 false true在海湾合作委员会。换句话说,带有初始化程序的捕获变为 const在 GCC 中,但不在 Clang 中。

关于c++ - lambda 中值捕获的 std::move() 上的 decltype() 导致类型不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60220511/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com