I believe I understand the concept of perfect forwarding in C++. But I'm missing something similar for "this". Let's have:
class X {
std::vector<int> vec;
public:
std::vector<int> const &getVec() const & { return vec; }
std::vector<int> & getVec() & { return vec; }
std::vector<int> getVec() && { return std::move(vec); }
};
As std::forward()
compresses similar definitions for parameters, I'd like to have something similar for "this". Something like:
class X {
std::vector<int> vec;
public:
auto &&getVec() /*???const &*/ { return thisForward(vec); }
};
Is something like the above possible (or available in STL or boost)? Or, at least, is there some workaround?
Plus an additional question (just for verification), does my 3 overloads of getVec()
above make a sense? Is it okay (for optimization reasons) to have such 3 overloads? (Assume "X" is a container-like class.)
For C++20, you can get close but I don't see how doing exactly what you ask is possible.
If you are willing to turn get
into a static/friend function it works. I couldn't get the repetition of a helper type down to zero, but maybe this can be improved on. If you are willing to pay a reference member, this can likely be achieved with a wrapper but that wrapper would have to store a reference to the member.
#pragma once
#include <type_traits>
template <typename T>
concept lvalue = std::is_lvalue_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>;
template <typename T>
concept lcvalue = std::is_lvalue_reference_v<T> && std::is_const_v<std::remove_reference_t<T>>;
template <typename T, typename R>
struct RT {
using type = R;
};
template <lvalue T, typename R>
struct RT<T,R> {
using type = std::add_lvalue_reference_t<std::remove_const_t<R>>;
};
template <lcvalue T, typename R>
struct RT<T,R> {
using type = std::add_lvalue_reference_t<std::add_const_t<R>>;
};
template <typename T, typename R>
using RT_t = typename RT<T,R>::type;
Example:
#include <vector>
#include <cassert>
#include "rt.h"
namespace {
struct X {
std::vector<int> v;
template <typename Self>
friend RT_t<Self,std::vector<int>> get(Self&& self) {
return std::forward<RT_t<Self,std::vector<int>>>(self.v);
}
};
}
int main() {
X x{std::vector{1,2,3}};
assert(x.v.size() == 3);
X& xr = x;
get(xr).push_back(1);
assert(x.v.size() == 4);
//X const& xc = x;
//get(xc).push_back(1); // does not compile
{
std::vector<int> vec = get(std::move(x));
assert(vec.size() == 4);
}
assert(x.v.size() == 0);
}
So, downsides:
get(x)
instead of x.get()
get
one has to repeat RT_t<Self,std::vector<int>>
As of C++23 it will be possible to declare the this parameter explicitly . Then you will be able to do what you are asking for:
class X {
std::vector<int> vec;
public:
template<class Self>
decltype(auto) getVec(this Self&& self) {
return std::forward<Self>(self).vec;
}
};
You can read more here .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.