定义一个工厂函数,该函数返回指向在此工厂函数中创建的函数的指针

时间:2019-07-11 13:43:10

标签: c++ c++11

我的问题是:如何定义一个带有参数并返回指向根据该参数创建的函数的函数指针的工厂函数? (或其他获得相同结果的好方法)


说明

本质上,我想定义一个工厂函数set,该函数接受一个std::string参数str,并返回一个指向函数pf的指针。函数指针pf指向刚在set中创建的函数,该函数采用std::ostream &并返回std::ostream &

这样,我想用std::cout << set(str) << "text" << std::endl;打电话。我希望set(str)的结果至少与该语句一样长。

仅供参考,来自cplusplus

  

ostream & operator<< (ostream & (*pf)(ostream &));


更多说明

这是一个真实的例子,如下所示。

首先我有机械手

std::ostream & black(std::ostream & os)
{
    return os << "\033[30m";            // make terminal text black
}

std::ostream & red(std::ostream & os)
{
    return os << "\033[31m";            // make terminal text red
}

std::ostream & green(std::ostream & os)
{
    return os << "\033[32m";            // make terminal text green
}

这样我打电话给

std::cout << red << "this text is in red" << std::endl;

我将取得理想的效果。到目前为止一切顺利。

现在有地图

std::map<std::string, std::string> code =
{
    {"black", "30"},
    {"red", "31"},
    {"green", "32"}
    // ...
    // could extend much longer as there are many colors
};

我希望通过foo("red")

达到类似的自定义效果
void foo(std::string str)
{
    std::cout << set(str) << ("this text is in " + str) << std::endl;
}

其中set"red"并在地图code中查找对应的代码"31"

但是我在实现set函数时遇到问题。如果有人可以帮助我,我将不胜感激!

两个注意事项:

  1. 如果可能,我想为set函数提供好的性能,因为它将被反复调用。

  2. 如果我认为错误的方式请原谅我--只要您可以为set实现功能,我就不介意您以其他方式来实现。 / strong>

感谢您阅读这篇长文章。非常感谢你!

3 个答案:

答案 0 :(得分:3)

正在思考错误的方式。您需要做的是创建自己的参数化操纵器。可以将此类操纵器实现为单独的类,而您必须为此类重载operator<<

struct set_color
{
    std::string name;
    explicit set_color(std::string name)
        : name(std::move(name)) { }
    friend std::ostream & operator<<(std::ostream & os, const set_color &color)
    {
        if (color.name == "black")
            os << "\033[30m";
        else if ... // and so on
            ...
    }
}

您可以使用map来将名称转换为颜色代码,但是基本思想是不需要为此创建一堆函数。

答案 1 :(得分:2)

为什么要使事情变得复杂?

std::string_view color_from_name(std::string_view colorName)
{
    static const std::map<std::string_view, std::string_view> colors {
        {"red"sv, "\033[31m"sv},
        {"green"sv, "\033[32m"sv},
        {"black"sv, "\033[30m"sv},
    };
    return colors.at(colorName);
}

int main() {
    std::cout << color_from_name("red") << "tada" << color_from_name("green") << "got it\n";

    return 0;
}

https://wandbox.org/permlink/nh2qMKoovh2qVlk2

答案 2 :(得分:1)

我认为您可以这样全局定义sftp的另一个重载:

operator<<
using Manipulator = std::function<std::ostream&(std::ostream&)>;
std::ostream& operator<< (std::ostream& stream, Manipulator&>& func) {
    return func(stream);
}

如果您将字符串映射存储为lambda函数作为操纵器,则应该能够使std::map<std::string, Manipulator> manipulators; for (const auto& val : data) { manipulators.emplace(std::pair<std::string, Manipulator>(val.first, [&](std::ostream& out) -> std::ostream& { return out << "\033[" << val.second << "m"; } )); } 函数成为返回lambda的简单包装器。