Определить фабричную функцию, которая возвращает указатель на функцию, созданную в этой фабричной функции - PullRequest
1 голос
/ 11 июля 2019

Мой вопрос: как определить фабричную функцию, которая принимает параметр и возвращает указатель функции, указывающий на функцию, которая создается в соответствии с этим параметром? (или любой другой хороший способ достичь того же результата)


Объяснение

По сути, я хочу определить фабричную функцию 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, я не против, чтобы вы делали это по-другому.

Спасибо, что прочитали этот длинный пост. Большое спасибо!

Ответы [ 3 ]

3 голосов
/ 11 июля 2019

Вы думаете об этом неправильно.Вместо этого вам нужно создать собственный параметризованный манипулятор.Такой манипулятор может быть реализован как отдельный класс, для которого вам нужно перегрузить 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 для преобразования имени в цветовой код, но основная идея заключается в том, чтодля этого не нужно создавать кучу функций.

2 голосов
/ 11 июля 2019

Зачем все усложнять?

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

1 голос
/ 11 июля 2019

Я думаю, что вы можете глобально определить другую перегрузку operator<< как таковую:

using Manipulator = std::function<std::ostream&(std::ostream&)>;
std::ostream& operator<< (std::ostream& stream, Manipulator&>& func) {
    return func(stream);
}
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"; }
    ));
}

Если вы сохранили карту строк для лямбда-функций в качестве ваших манипуляторов, вы сможете сделать вашу set() функцию простой оболочкой, возвращающей вашу лямбду.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...