考虑以下代码:
#include <initializer_list>
#include <vector>
auto cref_lambda = [] (const auto& il){
using T= typename decltype(il)::value_type;
};
auto cval_lambda = [] (const auto il){
using T=typename decltype(il)::value_type;
};
int main(){
std::initializer_list<int> il;
cref_lambda(il);
cval_lambda(il);
}
cref_lambda 无法编译,因为我们试图将::转化为引用。
我知道解决方法(使用 std::remove_reference_t
或仅使用 decltype(*il.begin());
)但我想知道是否有在这里使用更好的成语。
最佳答案
解决手头问题的方法是添加 std::decay_t
到 decltype
操作说明。来自 cppreference :
Applies lvalue-to-rvalue, array-to-pointer, and function-to-pointer implicit conversions to the type T, removes cv-qualifiers, and defines the resulting type as the member typedef type.
最重要的是,它充当不符合上述任何注解的类型的标识。因此写是安全的
using T = typename std::decay_t<decltype(il)>::value_type;
获取不合格value_type
, 独立于函数签名。
现在到你问题的另一部分,如何写得更短。好吧,就您的示例而言,可以说,由于您的 lambda 不捕获任何内容,因此也可以用免费的函数模板替换它。
template < typename T >
void cref(std::initializer_list<T> const &il) {
/* use T and il */
}
或者它是否适用于任何容器
template < typename U >
void cref(U const &il) {
using T = typename U::value_type;
/* use T and il */
}
第一种情况的明显优势是,您可以访问 T = value_type
“免费”。另一个优点(在我看来)是如果你不小心用不是 std::initializer_list<T>
的东西调用这个函数,你会得到一个更清晰的编译器错误。 .您可以通过添加 static_assert
来弥补 lambda 的这个缺点。但这会进一步拉紧您最初想要找到的“短缺”。
最后,如果您真的喜欢 lambda 风格的函数编写方式,或者您必须捕获一些东西并且不能使用自由函数方法,您可能需要考虑使用模板 lambda 的 GCC 扩展:
auto cref_lambda = [] <typename U> (U const &il){
using T = typename U::value_type;
};
这可能是您可以获得的最短时间。
关于c++ - 有没有优雅的方式在多态 lambda 中编写类型别名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50126256/