有什么区别
template <typename T> void func( T t ) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
和使用带有自动参数的lambdas的C++ 14替代方案?
auto func = []( auto t ) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
应该首选哪一个?
我研究了泛型lambdas,稍微修改了这个例子,所以我的lambda应该捕获上层lambda的可变参数包.所以基本上给予上层lambda的是(auto&&...)- 应该以某种方式在[=]块中捕获.
(完美的转发是另一个问题,我很好奇这可能在这里吗?)
#include <iostream>
#include<type_traits>
#include<utility>
// base case
void doPrint(std::ostream& out) {}
template <typename T, typename... Args>
void doPrint(std::ostream& out, T && t, Args && ... args)
{
out << t << " "; // add comma here, see below
doPrint(out, std::forward<Args&&>(args)...);
}
int main()
{
// generic lambda, operator() is a template with one parameter
auto vglambda = [](auto printer) {
return [=](auto&&... ts) // generic lambda, ts is a parameter pack
{ …Run Code Online (Sandbox Code Playgroud) 我试图在内部lambda中捕获一个可变参数的lambda参数,并在其中使用它。例如,考虑以下代码:
int main () {
auto first = [&] (auto&&... one) {
auto second = [&] (auto&&... two) {
return ((one * two) + ...);
};
return second(one...);
};
return first(5);
}
Run Code Online (Sandbox Code Playgroud)
这适用于gcc9,但不适用于clang8(https://godbolt.org/z/i2K9cK)。
使代码编译的一种方法是显式捕获[&one...],但是我想知道这是否是clang中的错误。
也很有趣:将return语句更改one为直接扩展的内容(与结合之前two),然后再次编译:
return (((one * ...) * two) + ...);
我找到了这个相关的帖子,但是声明在那里的错误似乎在clang8中已修复。
我实现了一个Visit函数(在变体上),该函数检查变体中当前活动的类型是否与函数签名(更确切地说是第一个参数)匹配。基于这个不错的答案。例如
#include <variant>
#include <string>
#include <iostream>
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v){
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove …Run Code Online (Sandbox Code Playgroud) c++ template-meta-programming variadic-templates generic-lambda c++17
可以通过访问它来推断出非泛型lambda的arity operator().
template <typename F>
struct fInfo : fInfo<decltype(&F::operator())> { };
template <typename F, typename Ret, typename... Args>
struct fInfo<Ret(F::*)(Args...)const> { static const int arity = sizeof...(Args); };
Run Code Online (Sandbox Code Playgroud)
对于像没有模板化的东西一样[](int x){ return x; },这很好看operator().
但是,通用lambdas operator()会对模板进行模板化,并且只能访问模板的具体实例 - 这有点问题,因为我无法手动提供模板参数,operator()因为我不知道它是什么.
所以,当然,像
auto lambda = [](auto x){ return x; };
auto arity = fInfo<decltype(lambda)>::arity;
Run Code Online (Sandbox Code Playgroud)
不起作用.
我不知道要投射什么,也不知道提供什么模板参数(或多少)(operator()<??>).
任何想法如何做到这一点?
以下C++代码标准是否兼容?
#include <iostream>
int main()
{
[](auto v){ std::cout << v << std::endl; }.operator()<int>(42);
}
Run Code Online (Sandbox Code Playgroud)
既铛++ 3.8.0和克++ 7.2.0 编译该代码细(编译器标志-std=c++14 -Wall -Wextra -Werror -pedantic-errors).
我可以写一个函数模板:
template<typename T>
void f1(T parameter) { ... }
Run Code Online (Sandbox Code Playgroud)
但是在C++ 14中,我还可以创建一个通用的lambda:
auto f2 = [](auto parameter) { ... };
Run Code Online (Sandbox Code Playgroud)
在f1可以参考我T直接.在内部f2,没有T可以参考,但我可以使用decltype以下方式获得相同的效果:
auto f2 = [](auto parameter)
{
using T = decltype(param);
...
};
Run Code Online (Sandbox Code Playgroud)
通用lambda的一个优点是我可以完美地转发它.我不能用功能模板做到这一点:
template<typename T>
void fwdToG(T&& param) { g(std::forward<T>(param)); }
fwdToG(f1); // error!
fwdToG(f2); // okay
Run Code Online (Sandbox Code Playgroud)
是否存在使用函数模板比使用通用lambda更好的情况?
我有这样的功能:
void loadData(std::function<void (std::string, std::string, std::string)> callback)
{
// data loading stuff
callback(body, subject, header);
}
Run Code Online (Sandbox Code Playgroud)
问题是我并不需要使用subject,并header在我的回调函数.现在我正在以这种方式处理它:
loadData([](std::string body, std::string, std::string){
std::cout << body;
})
Run Code Online (Sandbox Code Playgroud)
我想用它替换它
loadData([](std::string body){
std::cout << body;
})
Run Code Online (Sandbox Code Playgroud)
并自动传递给回调函数尽可能多的参数.我不想loadData为所有3个可能的参数计数手动重载函数.我也不想在调用站点上使用任何更复杂的lambda语法,因为我的库应该清楚,供其他人使用.这可能使用C++ STL和Boost吗?
考虑这个伪代码段:
class SomeClass
{
public:
SomeClass()
{
if(true)
{
fooCall = [](auto a){ cout << a.sayHello(); };
}
else
{
fooCall = [](auto b){ cout << b.sayHello(); };
}
}
private:
template<typename T>
std::function<void(T)> fooCall;
};
Run Code Online (Sandbox Code Playgroud)
我想要的是一个fooCall存储泛型lambda 的类成员,而lambda又在构造函数中赋值.
编译器抱怨fooCall不能是模板化的数据成员.
关于如何在类中存储泛型lambda,有没有简单的解决方案?
C++ 标准专家的几个相关问题。
传入的 C++20引入了模板 lambdas ( P0428R2 )。
所以代替
auto x = [](auto x, auto y){ return x+y; };
Run Code Online (Sandbox Code Playgroud)
我们可以指定模板参数如下
auto x = []<typename T>(T x, T y){ return x+y; };
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好。
第一个问题:模板 lambda 中的显式模板参数是否只能从参数中推导出来,或者是否可以添加非推导出的模板参数?
阅读 P0428r1 我没有看到任何明确的限制,但是,我也没有看到非推导模板参数的例子。
在第一个近似值中,我认为非推导的模板参数是合法的,因为我看到以下愚蠢的代码
int main()
{
[]<int = 0>(){ }();
}
Run Code Online (Sandbox Code Playgroud)
使用 g++(10.0.0 head)和 clang++(10.0.0 head)编译和运行。
假设允许非推导的模板参数,第二个问题是:如何在提供模板参数的同时调用模板 lambda?
举例:给定以下模板 lambda
auto x = []<std::size_t I>(auto t){ return std::get<I>(t); };
Run Code Online (Sandbox Code Playgroud)
I在没有显式命名的情况下调用此类 lambda 时,是否有一些语法用于指定模板参数operator()?
我试过
x<0u>(y);
Run Code Online (Sandbox Code Playgroud)
但 …
generic-lambda ×10
c++ ×9
c++14 ×6
lambda ×6
templates ×2
c++11 ×1
c++17 ×1
c++20 ×1
std-function ×1