我一直试图了解何时何时不具有捕获默认odr的lambda-使用在其周围范围内定义的自动存储持续时间的变量(由this answer提示)。在探索周围时,我偶然发现了一点点好奇心。 GCC和Clang似乎不同意以下代码中id-expression n
的值类别:
template <typename T> void assert_is_lvalue(const T&) {}
template <typename T> void assert_is_lvalue(const T&&) = delete;
int main() {
const int n = 0;
[=] { assert_is_lvalue(n); };
}
Clang成功编译代码,而GCC不编译(error: use of deleted function
)。哪一个是正确的?或者这是未指定的或实现定义的东西?
绑定对象的引用应该使用它,并且通过删除lambda的capture-default并观察两个编译器然后抱怨n
无法在没有捕获的情况下隐式捕获 - 默认值。
将lambda标记为mutable
对编译器的输出没有明显的影响。
答案 0 :(得分:2)
事实证明,gcc行为已从gcc-7.5向上改变!我使用以下代码查看如何在lambda中捕获n以及匹配哪个模板。
#include <iostream>
#include <string>
#include <typeinfo>
#include <type_traits>
#include <memory>
#include <string>
#include <cstdlib>
template <class T>
constexpr std::string_view type_name()
{
using namespace std;
#ifdef __clang__
string_view p = __PRETTY_FUNCTION__;
return string_view(p.data() + 34, p.size() - 34 - 1);
#elif defined(__GNUC__)
string_view p = __PRETTY_FUNCTION__;
#if __cplusplus < 201402
return string_view(p.data() + 36, p.size() - 36 - 1);
#else
return string_view(p.data() + 49, p.find(';', 49) - 49);
#endif
#elif defined(_MSC_VER)
string_view p = __FUNCSIG__;
return string_view(p.data() + 84, p.size() - 84 - 7);
#endif
}
template <typename T>
void assert_is_lvalue(const T& param)
{
std::cout << " T is " << type_name<T>()
<< " param is " << type_name<decltype(param)>() << '\n';
}
//template <typename T> void assert_is_lvalue(const T&&) = delete;
template <typename T>
void assert_is_lvalue(const T&& param)
{
std::cout << " T is " << type_name<T>()
<< " param is " << type_name<decltype(param)>() << '\n';
}
int main()
{
const int n = 0;
[=] {
std::cout << " n is " << type_name<decltype(n)>() << '\n';
assert_is_lvalue(n);
}();
return 0;
}
结果如下:
gcc-7.5
n is const int
T is int param is const int&&
gcc-8.1
n is const int
T is int param is const int&
您可以使用代码here。