Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No matching function for call std::forward(const std::string &) with variadic arguments

Tags:

c++

c++11

I'm trying to make a movable wrapper to non-copyable, non-movable class, however I have a problem passing a const std::string variable to the constructor. The minimal example below produces following error:

#include <iostream>
#include <memory>
#include <string>
#include <utility>

struct X {
    std::string x;

    X(const std::string &x) : x(x) {}
    X(const X &x) = delete;
    X(X &&x) = delete;
};

struct Wrapper {
    std::unique_ptr<X> x;

    Wrapper(const Wrapper & wrapper) = delete;
    Wrapper(Wrapper && wrapper) = default;

    template<typename... Args>
    Wrapper(Args&&... args) : x(std::make_unique<X>(std::forward(args)...)) {}
};

int main() {
    const std::string XXX = "XXX";
    Wrapper w{XXX};
    std::cout << w.x->x << std::endl;
}

Error message here:

forwarding.cc:21:53: error: no matching function for call to 'forward'
    Wrapper(Args&&... args) : x(std::make_unique<X>(std::forward(args)...)) {}
                                                    ^~~~~~~~~~~~
forwarding.cc:26:13: note: in instantiation of function template specialization 'Wrapper::Wrapper<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > &>' requested here
    Wrapper w{XXX};
            ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/move.h:73:5: note: candidate template ignored: couldn't infer template argument '_Tp'
    forward(typename std::remove_reference<_Tp>::type& __t) noexcept
    ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/move.h:84:5: note: candidate template ignored: couldn't infer template argument '_Tp'
    forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
    ^
1 error generated.
like image 624
Erbureth Avatar asked Jan 29 '18 12:01

Erbureth


1 Answers

You need to explicitly pass template parameters to std::forward:

std::forward<Args>(args)...

This is because std::forward needs some way of knowing the "original value category" of args..., which is impossible through template argument deduction alone as args is always an lvalue.

Lvalues will deduced as lvalue references in the context of template argument deduction for forwarding references (as a special rule), so std::forward can do its job by looking at the types inside Args....

like image 147
Vittorio Romeo Avatar answered Oct 31 '22 06:10

Vittorio Romeo