使用包扩展的 Lambda 继承
Lambda inheritance using pack expansion
我正在研究 lambda 继承,我尝试更改以下示例
在这个 Whosebug link 下。我使用模板推导指南和折叠表达式修改了代码。
这段代码
#include <iostream>
using namespace std;
template<class... Ts>
class FunctionSequence :Ts...
{
using Ts::operator()...;
};
template <class...Ts> FunctionSequence(Ts...) -> FunctionSequence<Ts...>; // (1)
int main(){
//note: these lambda functions are bug ridden. Its just for simplicity here.
//For correct version, see the one on coliru, read on.
auto trimLeft = [](std::string& str) -> std::string& { str.erase(0, str.find_first_not_of(' ')); return str; };
auto trimRight = [](std::string& str) -> std::string& { str.erase(str.find_last_not_of(' ')+1); return str; };
auto capitalize = [](std::string& str) -> std::string& { for(auto& x : str) x = std::toupper(x); return str; };
auto trimAndCapitalize = FunctionSequence{trimLeft, trimRight, capitalize};
std::string str = " what a Hullabaloo ";
std::cout << "Before TrimAndCapitalize: str = \"" << str << "\"\n";
trimAndCapitalize(str);
std::cout << "After TrimAndCapitalize: str = \"" << str << "\"\n";
return 0;
}
但是我收到以下错误
<source>: In function 'int main()':
<source>:19:78: error: no matching function for call to 'FunctionSequence<main()::<lambda(std::string&)>, main()::<lambda(std::string&)>, main()::<lambda(std::string&)> >::FunctionSequence(<brace-enclosed initializer list>)'
19 | auto trimAndCapitalize = FunctionSequence{trimLeft, trimRight, capitalize};
| ^
<source>:5:7: note: candidate: 'constexpr FunctionSequence<main()::<lambda(std::string&)>, main()::<lambda(std::string&)>, main()::<lambda(std::string&)> >::FunctionSequence(const FunctionSequence<main()::<lambda(std::string&)>, main()::<lambda(std::string&)>, main()::<lambda(std::string&)> >&)'
5 | class FunctionSequence :Ts...
| ^~~~~~~~~~~~~~~~
<source>:5:7: note: candidate expects 1 argument, 3 provided
<source>:5:7: note: candidate: 'constexpr FunctionSequence<main()::<lambda(std::string&)>, main()::<lambda(std::string&)>, main()::<lambda(std::string&)> >::FunctionSequence(FunctionSequence<main()::<lambda(std::string&)>, main()::<lambda(std::string&)>, main()::<lambda(std::string&)> >&&)'
<source>:5:7: note: candidate expects 1 argument, 3 provided
ASM generation compiler returned: 1
出了什么问题?
代码示例 --> demo
using Ts::operator()...;
这会将所有 operator()
从基础 class 中“提升”到 class 命名空间中。
这显然不是您想要的。看起来您想按顺序执行组成基数-class 操作。
以下是使用逗号运算符以巧妙的方式编写的方法:
template<class... Ts>
struct FunctionSequence : Ts... {
auto operator()(std::string& str) const {
return (Ts::operator()(str), ...);
}
};
#include <iostream>
using namespace std;
template<class... Ts>
struct FunctionSequence : Ts... {
auto operator()(std::string& str) const {
return (Ts::operator()(str), ...);
}
};
template <class...Ts> FunctionSequence(Ts...) -> FunctionSequence<Ts...>; // (1)
int main(){
//note: these lambda functions are bug ridden. Its just for simplicity
//here. For correct version, see the one on coliru, read on.
auto trimLeft = [](std::string& str) -> std::string& { str.erase(0, str.find_first_not_of(' ')); return str; };
auto trimRight = [](std::string& str) -> std::string& { str.erase(str.find_last_not_of(' ')+1); return str; };
auto capitalize = [](std::string& str) -> std::string& { for(auto& x : str) x = std::toupper(x); return str; };
auto trimAndCapitalize = FunctionSequence{trimLeft, trimRight, capitalize};
std::string str = " what a Hullabaloo ";
std::cout << "Before TrimAndCapitalize: str = \"" << str << "\"\n";
trimAndCapitalize(str);
std::cout << "After TrimAndCapitalize: str = \"" << str << "\"\n";
return 0;
}
版画
Before TrimAndCapitalize: str = " what a Hullabaloo "
After TrimAndCapitalize: str = "WHAT A HULLABALOO"
备注
我建议私有继承,并使函数要么对参数进行无效操作,要么使它们成为纯函数(获取常量引用并返回副本)。另外,参见 function composition in C++ / C++11 例如
我正在研究 lambda 继承,我尝试更改以下示例 在这个 Whosebug link 下。我使用模板推导指南和折叠表达式修改了代码。
这段代码
#include <iostream>
using namespace std;
template<class... Ts>
class FunctionSequence :Ts...
{
using Ts::operator()...;
};
template <class...Ts> FunctionSequence(Ts...) -> FunctionSequence<Ts...>; // (1)
int main(){
//note: these lambda functions are bug ridden. Its just for simplicity here.
//For correct version, see the one on coliru, read on.
auto trimLeft = [](std::string& str) -> std::string& { str.erase(0, str.find_first_not_of(' ')); return str; };
auto trimRight = [](std::string& str) -> std::string& { str.erase(str.find_last_not_of(' ')+1); return str; };
auto capitalize = [](std::string& str) -> std::string& { for(auto& x : str) x = std::toupper(x); return str; };
auto trimAndCapitalize = FunctionSequence{trimLeft, trimRight, capitalize};
std::string str = " what a Hullabaloo ";
std::cout << "Before TrimAndCapitalize: str = \"" << str << "\"\n";
trimAndCapitalize(str);
std::cout << "After TrimAndCapitalize: str = \"" << str << "\"\n";
return 0;
}
但是我收到以下错误
<source>: In function 'int main()':
<source>:19:78: error: no matching function for call to 'FunctionSequence<main()::<lambda(std::string&)>, main()::<lambda(std::string&)>, main()::<lambda(std::string&)> >::FunctionSequence(<brace-enclosed initializer list>)'
19 | auto trimAndCapitalize = FunctionSequence{trimLeft, trimRight, capitalize};
| ^
<source>:5:7: note: candidate: 'constexpr FunctionSequence<main()::<lambda(std::string&)>, main()::<lambda(std::string&)>, main()::<lambda(std::string&)> >::FunctionSequence(const FunctionSequence<main()::<lambda(std::string&)>, main()::<lambda(std::string&)>, main()::<lambda(std::string&)> >&)'
5 | class FunctionSequence :Ts...
| ^~~~~~~~~~~~~~~~
<source>:5:7: note: candidate expects 1 argument, 3 provided
<source>:5:7: note: candidate: 'constexpr FunctionSequence<main()::<lambda(std::string&)>, main()::<lambda(std::string&)>, main()::<lambda(std::string&)> >::FunctionSequence(FunctionSequence<main()::<lambda(std::string&)>, main()::<lambda(std::string&)>, main()::<lambda(std::string&)> >&&)'
<source>:5:7: note: candidate expects 1 argument, 3 provided
ASM generation compiler returned: 1
出了什么问题?
代码示例 --> demo
using Ts::operator()...;
这会将所有 operator()
从基础 class 中“提升”到 class 命名空间中。
这显然不是您想要的。看起来您想按顺序执行组成基数-class 操作。
以下是使用逗号运算符以巧妙的方式编写的方法:
template<class... Ts>
struct FunctionSequence : Ts... {
auto operator()(std::string& str) const {
return (Ts::operator()(str), ...);
}
};
#include <iostream>
using namespace std;
template<class... Ts>
struct FunctionSequence : Ts... {
auto operator()(std::string& str) const {
return (Ts::operator()(str), ...);
}
};
template <class...Ts> FunctionSequence(Ts...) -> FunctionSequence<Ts...>; // (1)
int main(){
//note: these lambda functions are bug ridden. Its just for simplicity
//here. For correct version, see the one on coliru, read on.
auto trimLeft = [](std::string& str) -> std::string& { str.erase(0, str.find_first_not_of(' ')); return str; };
auto trimRight = [](std::string& str) -> std::string& { str.erase(str.find_last_not_of(' ')+1); return str; };
auto capitalize = [](std::string& str) -> std::string& { for(auto& x : str) x = std::toupper(x); return str; };
auto trimAndCapitalize = FunctionSequence{trimLeft, trimRight, capitalize};
std::string str = " what a Hullabaloo ";
std::cout << "Before TrimAndCapitalize: str = \"" << str << "\"\n";
trimAndCapitalize(str);
std::cout << "After TrimAndCapitalize: str = \"" << str << "\"\n";
return 0;
}
版画
Before TrimAndCapitalize: str = " what a Hullabaloo "
After TrimAndCapitalize: str = "WHAT A HULLABALOO"
备注
我建议私有继承,并使函数要么对参数进行无效操作,要么使它们成为纯函数(获取常量引用并返回副本)。另外,参见 function composition in C++ / C++11 例如