vendredi 23 février 2018

Cannot call std::invoke() with auto& parameter via std::ref()

I am trying to create a Invoker object which stores both a functor and a set of parameters for this functor - all by value (used for threading). Invoker::operator()() will call the stored functor with the copied parameters.

Everything is working fine so far, until one tries to pass a parameter by auto& using std::ref(variable). Specifically this code should work, but instead it does not compile with the given error message:

int var = 0;
Invoker{
    [](auto& ref) {
        printf("%d\n");
    }, std::ref(var)
}();

I expect it to work similar to how std::thread works with this example. The error message is:

test.cpp:65:14: error: no matching function for call to ‘invoke(std::__tuple_element_t<0, std::tuple<main()::<lambda(auto:1&)>, std::reference_wrapper<int> > >, std::__tuple_element_t<1, std::tuple<main()::<lambda(auto:1&)>, std::reference_wrapper<int> > >)’
   std::invoke(std::get<Indicies>(std::move(args))...);
   ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

My current Invoker class:

template<typename... Args>
struct Invoker {
    std::tuple<std::decay_t<Args>...> args;

    explicit Invoker(Args... args)
        : args(std::forward<Args>(args)...)
    { }

    template<size_t... Indices>
    void _Invoke(std::index_sequence<Indices...>) {
        std::invoke(std::get<Indices>(std::move(args))...);
    }

    void operator()() {
        _Invoke(std::make_index_sequence<std::tuple_size_v<decltype(args)>>{});
    }
};

/* Invoker deduction guide (perfectly forward any parameters with full type!) */
template<typename Function, typename... Args>
Invoker(Function&&, Args&&...) -> Invoker<Function&&, Args&&...>;

See here for an online version of this problem. The error message suggests, that the deduced type of auto& is std::reference_wrapper<int>&, when it should be int&. Unfortunately I cannot come up with a solution to this problem.

Aucun commentaire:

Enregistrer un commentaire