如何在C ++中将函数列表应用于字符串?

时间:2019-01-31 15:09:20

标签: c++ algorithm

我有一系列需要加成作用于单个字符串的功能的清单。如何表达“应用”功能。

const counter = 0

router.get("/", (req, res) => {
  counter++
  res.send({counter: counter})
})

在c ++中?

字符串是std :: string

8 个答案:

答案 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«。

由于上述构造区分了InputTOutputT,因此您可以“混合”类型,如下所示:

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&&>;

我们可以按如下方式使用此包装器类。

DEMO

auto outPutString = arg(inputString)
                      .Apply(Transformation1)
                      .Apply(Transformation2)
                      .get();

Lambda也可以通过这种方式工作。 以下结果outPut13

DEMO(lambda)

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!"

DEMO

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;
}