Как запустить определенные c функции на основе тегов в C ++? - PullRequest
1 голос
/ 28 мая 2020

Я пишу тестовую среду, которая будет запускать сотни тестов. Каждый из этих тестов был написан как независимая функция. В настоящее время моя основная функция запускает каждый из этих тестов один за другим. Я хотел бы создать систему, использующую теги. Например, я хочу иметь возможность запускать все тесты с тегом 'WiFi' или запускать все тесты с тегом 'notifications'.

Я пытался найти, как это сделать, но все Я могу найти статьи, в которых говорится об отправке тегов , что мне не помогает. Может быть, тег мне здесь не нужен?

Не уверен, имеет ли это значение, но я пишу на C ++ 11 на Ma c и использую VS Code.

кстати, я новичок в переполнении стека, извините, если я что-то испортил. Заранее спасибо!

Изменить: я бы использовал несколько тегов для каждой функции. Например, для одной функции требуются теги «WiFi» и «Сеть», а для другой - теги «Hapti c», «Уведомление» и «Сеть».

Ответы [ 2 ]

5 голосов
/ 28 мая 2020

Причина, по которой ваше исследование провалилось, состоит в том, что «тег» - это очень широкий, общий термин, который на самом деле не описывает то, что вы делаете.

По сути, вы пытаетесь сопоставить две части данных вместе; это действительно так. Не имеет значения, является ли одна из этих частей (ваш «тег») целым числом, членом перечисления, строкой, экземпляром класса или чем-то еще.

Вы сказали «Мне понадобится новая карта для каждого тега «», но я не согласен. Вам нужна только мульти-карта от «тега» к функциям (и, в худшем случае, еще одна мульти-карта от функций к «тегу», если вам также нужен обратный поиск). Это довольно тривиально.

enum class Tag
{
   WiFi,
   Haptic,
   Network,
   Notification
};

using Function = std::function<void()>;  // or whatever it is

std::multimap<Tag, Function> tagLookup;

void BindTag(const Tag tag, Function func)
{
   tagLookup.emplace(tag, std::move(func));  // I'm using move out of habit
}

void RunFuncsForTag(const Tag tag)
{
   auto [start, end] = tagLookup.equal_range(tag);
   for (auto it = start; it != end; ++it)
   {
      const Function& func = it->second;
      func();
   }
}

int main()
{
   BindTag(...);
   BindTag(...);

   RunFuncsForTag(tag);
}

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

1 голос
/ 28 мая 2020

Вы можете go с multimap, но вы также можете упростить его, используя всего один контейнер со всеми тестами:

#include <vector>
#include <type_traits>

template <class E> auto as_underlying(E e) -> std::underlying_type_t<E>
{ return static_cast<std::underlying_type_t<E>>(e); }

enum class Tag : unsigned {
    WiFi = 0x01u,
    Network = 0x02u,
    Haptic = 0x04u,
    Notification = 0x08u,
};

auto operator|(Tag lhs, Tag rhs) -> Tag
{
    return Tag{as_underlying(lhs) | as_underlying(rhs)};
}

struct Test
{
    using F = bool();

    Tag tag;
    F* test; // or std::function

    bool has_tag(Tag tag_to_check) const
    {
        return as_underlying(tag) & as_underlying(tag_to_check);
    }

    bool operator()() const { return test(); }
};

template <class Cont>
auto run_by_tag(const Cont& tests, Tag tag)
{
    for (const auto& test : tests)
    {
        if (test.has_tag(tag))
        {
            test();
        }
    }
}

auto test()
{
    std::vector<Test> tests{
        Test{Tag::WiFi | Tag::Network, [] { return true;}},
        Test{Tag::Haptic | Tag::Notification | Tag::Network, [] { return false; }},
        Test{Tag::Notification, [] { return true;}}
    };

    run_by_tag(tests, Tag::WiFi);
    run_by_tag(tests, Tag::Notification);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...