Search code examples
c++rvalueperfect-forwardingclang-tidy

Perfect forwarding interpreted as rvalue reference


My understanding was that ConcreteType&& was an rvalue and TemplateType&& was "perfect forwarding".

I'm trying to use perfect forwarding, but clang-tidy interprets it as rvalue reference.

clang and gcc don't complain, but clang-tidy marks it as parse error before doing any further analysis, so I'm not sure if it's an issue with the code or with clang-tidy.

I suspect it's related to the fact I'm using it in a constructor, but I'm not sure.

Minimum code:

#include <memory>

template <typename T>
class my_wrapper {
  T val;

 public:
  my_wrapper(T&& val_)
      : val{std::forward<T>(val_)} {}
};


struct my_struct {
  int x;
};

auto xyz() {
  my_struct ms{3};
  return my_wrapper<my_struct>(ms);
}

Error message:

Error while processing /path/foo.cpp.
/path/foo.cpp:20:25: error: no matching constructor for initialization of 'my_wrapper<my_struct>' [clang-diagnostic-error]
  my_wrapper<my_struct> wrap(ms);
                        ^
/path/foo.cpp:5:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'my_struct' to 'const my_wrapper<my_struct>' for 1st argument
class my_wrapper {
      ^
/path/foo.cpp:5:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'my_struct' to 'my_wrapper<my_struct>' for 1st argument
/path/foo.cpp:9:3: note: candidate constructor not viable: no known conversion from 'my_struct' to 'my_struct &&' for 1st argument
  my_wrapper(T&& val_)
  ^

Solution

  • T is fully resolved by the time the constructor is invoked, so it's not perfect forwarding anymore

    If you want perfect forwarding on a function, it has to be the function itself that's templated, not the enclosing class.

    Like so:

    template <typename T>
    class my_wrapper {
      T val;
    
    public:
      template<typename U>
      my_wrapper(U&& val_)
          : val{std::forward<U>(val_)} {}
    };