我有一系列需要加成作用于单个字符串的功能的清单。如何表达“应用”功能。
const counter = 0
router.get("/", (req, res) => {
counter++
res.send({counter: counter})
})
在c ++中?
字符串是std :: string
答案 0 :(得分:2)
从C ++ 11开始,您还可以使用可变参数模板编写一个Apply
函数:
template <typename OutputT, typename InputT>
OutputT Apply(const InputT &obj)
{
return obj;
}
template <typename OutputT, typename InputT, typename Func, typename... OtherFuncs>
OutputT Apply(const InputT &obj, Func f, OtherFuncs... other)
{
return Apply<OutputT, decltype(f(obj))>(f(obj), other...);
}
然后您可以按以下方式使用它:
auto res = Apply<std::string>(
"Hello",
[](const std::string &str) { return str + " "; }, // Applicator 1
[](const std::string &str) { return str + "World"; } // Applicator 2
);
在这种情况下,结果为»Hello World«。
由于上述构造区分了InputT
和OutputT
,因此您可以“混合”类型,如下所示:
auto res = Apply<size_t>(
"Hello",
[](const std::string &str) { return str + " World"; }, // Applicator 1
[](const std::string &str) { return str.size(); } // Applicator 2
);
这一次的结果是11
。
最后,如果您确实想使用链接语法,则可以编写一个包装初始对象并具有Apply
方法的类。
答案 1 :(得分:1)
赞:
auto outPutString = Transformation2(Transformation1(inputString));
答案 2 :(得分:1)
std::string manipulateString(std::string str) {/* do something */; return result;}
std::string manipulateStringAgain(std::string str) {/* do something else */; return result;}
std::string manipulateMe = "hello";
auto resultString = manipulateString(manipulateStringAgain(manipulateMe));
答案 3 :(得分:1)
我假设当您说“功能列表”时,是指在运行时有所不同。如果列表是静态的,则其他答案会更好。
#include <vector>
#include <string>
#include <functional>
#include <numeric>
std::vector<std::function<std::string(std::string)>> funcs = { Transformation1, Transformation2 }; // or gotten from wherever
auto output = std::accumulate(funcs.begin(), funcs.end(), input, [](auto acc, auto fun){ return fun(acc); });
答案 4 :(得分:0)
在C和C ++中,也可以定义指向函数的指针并创建指向函数的指针的向量。稍后,您可以使用所需的参数在循环内调用函数。如果您有兴趣了解详细信息,请告诉我。
答案 5 :(得分:0)
如果您想保留顺序,请创建一些包装类,然后在其中放置操作函数。例如:
#include <iostream>
#include <string>
using namespace std;
class StringManipulator
{
public:
StringManipulator(std::string str) : str(str) {}
operator std::string() {return str;}
StringManipulator& doSomething() {str += "1"; return *this;}
StringManipulator& doSomethingElse() {str += "2"; return *this;}
private:
std::string str;
};
int main() {
std::string result = StringManipulator("0").doSomething().doSomethingElse();
std::cout << result;
return 0;
}
输出为012
。
operator std::string
确保隐式转换。
答案 6 :(得分:0)
#include <vector>
#include <iostream>
// three funcitons with a string as the parameter
int funca(std::string& str)
{
std::cout << "funca:" << str << std::endl;
return 1;
}
int funcb(std::string& str)
{
std::cout << "funcb:" << str << std::endl;
return 2;
}
int funcd(std::string& str)
{
std::cout << "funcd:" << str << std::endl;
return 3;
}
int main()
{
// definition of the string
std::string str = "the string";
// declare vector of pointers to function returning an int and receiving a string as a parameter:
std::vector< int(*)(std::string&)> pf;
// load func pointers to vector:
pf.push_back(&funca);
pf.push_back(&funcb);
pf.push_back(&funcd);
//declare vector iterator:
std::vector<int (*)(std::string&)>::iterator it;
// iterate vector of func pointers:
for (it = pf.begin() ; it != pf.end(); ++it)
{
// function call using pointers and passing parameter str
// you can get return value as from 'normal' function
int ret = (*it)(str);
std::cout << "function returns:" << ret << std::endl;
}
}
/*
compiled and executed on ubuntu 18.04, output:
funca:the string
function returns:1
funcb:the string
function returns:2
funcd:the string
function returns:3
*/
答案 7 :(得分:0)
相似的语法可以通过下面的简单包装器类定义。 这使我们能够通过链接按正序编写函数。
在这里,我假设f(t)
仅具有一个参数,而没有void函数f()
或多参数函数f(t1,t2,...)
。
在这种情况下,会发生编译错误。
我应用std::is_invocable<F,T>
和double parentheses来检查F(T)
的格式是否正确,因为按右值引用f(std::move(t))
传递的函数调用语法是不同的和其他f(t)
。
这是我的实现方式
#include <utility>
#include <type_traits>
template <typename T>
class arg
{
T t;
public:
template <typename U>
explicit constexpr arg(U&& val)
: t(std::forward<U>(val))
{}
template <typename F>
constexpr auto Apply(F f)
{
if constexpr(std::is_invocable<F, decltype((t))>::value)
{
// f(t), f(t&) and f(const t&), no type deduction
return arg<decltype(f(t))>(f(t));
}
else
{
// f(&&t), no type deduction
return arg<decltype(f(std::move(t)))>(f(std::move(t)));
}
}
constexpr auto& get() const noexcept
{
return t;
}
};
template<class U>
arg(U&&) -> arg<U&&>;
我们可以按如下方式使用此包装器类。
auto outPutString = arg(inputString)
.Apply(Transformation1)
.Apply(Transformation2)
.get();
Lambda也可以通过这种方式工作。
以下结果outPut
为13
:
auto outPutString = arg("Hello")
.Apply([](std::string s){ return s + " World" ; })
.Apply([](std::string& s){ return s + "!" ; })
.Apply([](const std::string& s){ return s + "!" ; })
.Apply([](std::string&& s){ return std::make_shared<std::string>(s); })
.Apply([](auto s){ return std::make_unique<std::string>(*s); })
.Apply([](auto s){ return (*s).size(); })
.get();
不太高兴,但是我们也可以尝试如下使此类运行时正常工作。
输出"Hello world!"
std::string f1(const std::string& s)
{ return (s + " "); }
std::string f2(const std::string& s)
{ return (s + "World"); }
std::string f3(const std::string& s)
{ return (s + "!"); }
int main()
{
using arg_type = const typename std::string&;
using ret_type = typename std::string ;
std::vector<std::function<ret_type(arg_type)>> funcs = { f1, f2, f3 };
auto output = std::accumulate(
funcs.cbegin(), funcs.cend(), arg<ret_type>("Hello"),
[](auto a, auto f){
return a.Apply(f);
}).get();
std::cout << output << std::endl;
return 0;
}