Замена (или повторная реализация?) Std :: function для некоторой статистики и тестирования - PullRequest
0 голосов
/ 18 апреля 2019

У меня есть особый случай, где я хотел бы измерить статистику использования моей функции std :: function. Обычно такие вещи, как затраченное время, количество вызовов, какая функция вызывается часто, а также иногда для тестирования, например, случайный вызов nullptr для проверки того, как мой код обрабатывает его.

Сначала я думал о наследовании от std :: func, а затем переопределил функцию, которая извлекает указатель - или что-то в этом роде - но после прочтения нескольких тем и руководств я пришел к выводу, что это очень незаметно.

Моя вторая мысль - просто создать класс-оболочку. Рефакторинг всего моего кода для использования этой обертки вместо std :: function не составит труда, так что все в порядке. Все, чего я хочу избежать - это использовать ненужное и неудобное использование, как любую дополнительную функцию. eg.:

std::function<...> dummyvar (...);

// Later I can call this dummy var as simply as dummyvar(...)
// I don't want to add extra complexity, like this:

CustomWrapper<...> customdummy (...);
customdummy.getVal()(...);

// Best would be if I could actually "simply" replace all std::function to the Custom Wrapper.

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


Я понятия не имею, как продвигаться дальше, поэтому я даже не приложил никакого исходного кода.

Ответы [ 3 ]

2 голосов
/ 18 апреля 2019

Вы можете сделать что-то вроде:

template <typename Sig>
class CustomWrapper
{
private:
    std::function<Sig> f;
    mutable std::size_t nbCall = 0;
    // ...
public:
    CustomWrapper() = default;

    CustomWrapper(const CustomWrapper&) = default;
    CustomWrapper(CustomWrapper&&) = default;
    CustomWrapper& operator=(const CustomWrapper&) = default;
    CustomWrapper& operator=(CustomWrapper&&) = default;

    template <typename T,
              std::enable_if_t<!std::is_same<CustomWrapper, std::decay_t<T>>::value
                  && std::is_constructible<std::function<Sig>, T&&>::value, bool> = false>
    CustomWrapper(T&& arg) : f(std::forward<T>(arg)){}

    template <typename ... Ts,
              std::enable_if_t<(sizeof...(Ts) >= 2)
                  && std::is_constructible<std::function<Sig>, Ts&&...>::value, bool> = false>
    CustomWrapper(Ts&& ... args) : f(std::forward<Ts>(args)...){}

    template <typename ... Ts>
    auto operator ()(Ts&&... args) const -> decltype(f(std::forward<Ts>(args)...))
    {
        ++nbCall; // Statistics you want
        // ...
        return f(std::forward<Ts>(args)...);
    }

    std::size_t getNbCall() const { return nbCall; }
    // ...
};

Демо

1 голос
/ 18 апреля 2019

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

template <typename T>
class CustomWrapper;

template <typename Result, typename ...Args>
class CustomWrapper<Result(Args...)>
{
public:
    template <typename ...SomeArgs>
    CustomWrapper(SomeArgs&&... args)
     : func(std::forward<SomeArgs>(args)...) 
    {
    }

    CustomWrapper(const CustomWrapper&) = default;
    CustomWrapper(CustomWrapper&&) = default;

    auto operator()(Args&&... args)
    {
        return func(std::forward<Args>(args)...);
    }

private:
    std::function<Result(Args...)> func;
};

void foo()
{
    CustomWrapper<void(int, int)> func([](int x1, int x2) {});
    func(1, 2);
}

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

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

0 голосов
/ 18 апреля 2019

Вы хотите, чтобы он постоянно проверялся на статистику или только один раз перед отправкой вашей программы?Если только один раз, я бы порекомендовал использовать инструменты профилирования / покрытия, чтобы увидеть, сколько раз ссылается функция.

Если вам нужна постоянная статистика, вам нужно взглянуть на интерфейс std :: function (https://en.cppreference.com/w/cpp/utility/functional/function) и создатьНовая реализация для этого - это не так уж сложно реализовать.

...