我该如何申请的功能清单,字符串在C + +?

问题描述 投票:1回答:8

我有需要被累加应用于单个字符串函数列表。如何表达“应用”功能。

auto outPutString = inputString
.Apply(Transformation1)
.Apply(Transformation2)

在C ++?

该字符串是的std :: string

c++ algorithm
8个回答
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
投票

像这样:

auto outPutString = Transformation2(Transformation1(inputString));

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

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

0
投票

有可能在C和C ++,以及,以限定指针功能及创建指针载体的功能。稍后,您可以用所需参数的循环中调用功能。请让我知道如果你有兴趣了解详情。


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确保隐式转换。


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
*/

0
投票

类似的语法可以通过以下简单的包装类来定义。这使我们在写正顺序功能与链接。

  • 在这里,我认为f(t)刚刚一个参数,而不是一个空洞功能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;
}
© www.soinside.com 2019 - 2024. All rights reserved.