我注意到一个人被允许使用未在lambda中捕获的变量的编译时特征,例如调用sizeof
, decltype
函数,例如:
#include <iostream>
void f ()
{
}
int main()
{
int y = 13;
auto x = []{ return sizeof (decltype (y));};
std::cout << x () << 'n';
}
由于g++
和clang++
编译这个程序都没有错误,我想这是标准允许的。
这似乎有点误导我,即使我想不出任何特定的恶意情况下,它会导致一个错误。但是我想知道这个特性的实际用例是什么?
一个简单的例子,你可能会使用这是,如果你有一个lambda,你想执行计算相同类型的y
,因为你会将结果分配给y
。
同样,从另一个角度考虑:在[=]{ return x + sizeof (y);}
中捕获y
的好处是什么?这样做绝对没有意义,因为y
实际上并没有在lambda内部使用。捕获y
只会增加完全没有意义的开销。不仅如此,它甚至可能使编译器的内部工作复杂化,因为它们将不再能够简单地优化y
, sizeof(y)
不再在语义上等同于sizeof(int)
。
有时在嵌套作用域(lambda)中需要不带值的类型信息。你总是可以直接命名类型(或模板参数),如果你可以访问它,但总是有一个很好的建议,即如果有一天你改变了变量的类型,你不必在所有其他重复它的表达式中改变它。
例如:#include <iostream>
#include <tuple>
#include <utility>
class storage
{
public:
template<typename T>
auto make_getter(T value)
{
std::get<decltype(value)>(storage_) = value;
auto getter = [this]
{
return std::get<decltype(value)>(storage_);
};
return getter;
}
private:
std::tuple<int, char, double> storage_;
};
int main(void)
{
storage s;
auto getter = s.make_getter(42);
std::cout << getter() << std::endl;
}
这里你总是可以使用std::get<T>
而不是std::get<decltype(value)>
,但是如果有一天make_getter
不再是模板,它成为一个普通的函数,为每个类型的元组重载,而值的类型将更改为int
,这里的优点是decltype(value)
将始终工作,只要你不重命名变量。
无论如何,我认为这个功能的实用级别可能更多的是语义而不是技术。这种行为可能是从传统的规范
继承来的。char *buffer = malloc(42 * sizeof(*buffer));
C
语言中使用代替
char *buffer = malloc(42 *sizeof(char));
同样的原因。
同样,如果类型名是难以忍受的,并且由于某种原因你不想别名,你可以使用decltype方式,这并不一定意味着你想要关联的值