Say I have two overloads of a method in a class, set_value which each take a universal reference. I'd like to have one function call the other to avoid code duplication, but I'm not sure which is the correct way to give the universal reference to the other function.
template <typename U>
void set_value(U&& value) {
this->value_ = std::forward<U>(value);
}
template <typename U>
void set_value(U&& value, int overloaded) {
// which is the correct way to use the other `set_value` overload?
set_value(value); // just use value directly?
set_value(std::forward<U>(value)); // or should I forward it?
}
If you want perfect forwarding of value, use std::forward
Even though value might be bound to an rvalue, when you use it by name inside set_value it is an lvalue. Therefore, if you do set_value(value); the universal reference in the one-parameter overload would be bound to an lvalue reference.
We can confirm this by adding doing something like this:
template<class T> class TD; // Allows us to view type deduction results in
// the form of compilation errors.
// (From "Effective Modern C++")
...
template <typename U>
void set_value(U&& value) {
TD<decltype(value)> td;
}
...
int i;
set_value(i, 0);
set_value(3, 0);
When forwarding is used, this will give you a compilation error that will reveal the type of value to be int& for set_value(i, 0);. If you comment out that statement you'll get a compilation error for set_value(3, 0); revealing the type of value to be int&&.
If you remove the forwarding you'll get int& in both cases.
Related
The example on the page of std::ref/std::cref shows the use of std::ref/std::cref to pass arguments to std::bind in a way that looks like std::bind is taking arguments by reference, when in reality it takes the all by value.
Looking at that example only, I could also be ignorant about the existence of std::reference_wrapper, and std::ref would just be a function that allows the behavior exhibited by the linked example.
That's what I mean by std::ref works in the title of the question and also in the following.
Mostly for fun I've tried implementing std::ref myself, and I came up with this:
template<typename T>
struct ref_wrapper {
ref_wrapper(T& t) : ref(t) {}
T& ref;
operator T&() const {
return ref;
}
};
template<typename T>
ref_wrapper<T> ref(T& t) {
return ref_wrapper{t}; // Ooops
}
template<typename T>
ref_wrapper<const T> cref(const T& t) {
return ref_wrapper{t}; // Ooops
}
where on the lines marked as // Ooops I have mistakely made use of CTAD because I was compiling with -std=c++17. By changing ref_wrapper to ref_wrapper<T> and ref_wrapper<const T> in the two cases corrects this.
Then I've had a peek into /usr/include/c++/10.2.0/bits/refwrap.h.
On the one hand, I see that my implementation of ref/cref closely resembles that of std::ref/std::cref.
On the other hand, I see that std::reference_wrapper is around 60 lines long! There's a lot of stuff in there, including noexcept, macros, copy ctor, copy operator=, get.
I think most of that is not relevant to the use of std::reference_wrapper only as a slave to std::ref, but there's something which could be relevant, such as constructor taking a universal reference.
So my question is: what are the parts of std::reference_wrapper necessary and sufficients for std::ref to work, with respect to my skinny attempt?
I've just realized that there's a possible implementation of std::reference_wrapper on cppreference (which is less noisy than the one from GCC). Even here, however, there are things I don't undertand the reason of, such as operator().
The logic that you're talking about is implemented entirely within std::bind itself. The main functionality it needs from std::reference_wrapper is the fact that it can be "unwrapped" (i.e., you can call .get() on it in order to retrieve the underlying reference). When the call wrapper (i.e. object returned from std::bind) is called, it simply checks whether any of its bound arguments is a std::reference_wrapper. If so, it calls .get() to unwrap it, then passes the result to the bound callable.
std::bind is complicated because it is required to support various special cases, such as recursive binding (this feature is now considered a design mistake), so instead of trying to show how to implement the full std::bind, I'll show a custom bind template that's sufficient for the example on cppreference:
template <class Callable, class... Args>
auto bind(Callable&& callable, Args&&... args) {
return [c=std::forward<Callable>(callable), ...a=std::forward<Args>(args)] () mutable {
c(detail::unwrap_reference_wrapper(a)...);
};
}
The idea is that bind saves its own copy of the callable and each of the args. If an argument is a reference_wrapper, the reference_wrapper itself will be copied, not the referent. But when the call wrapper is actually invoked, it unwraps any saved reference wrapper argument. The code to do this is simple:
namespace detail {
template <class T>
T& unwrap_reference_wrapper(T& r) { return r; }
template <class T>
T& unwrap_reference_wrapper(reference_wrapper<T>& r) { return r.get(); }
}
That is, arguments that are not reference_wrappers are simply passed through, while reference_wrappers go through the second, more specialized overload.
The reference_wrapper itself merely needs to have a relevant constructor and get() method:
template <class T>
class reference_wrapper {
public:
reference_wrapper(T& r) : p_(std::addressof(r)) {}
T& get() const { return *p_; }
private:
T* p_;
};
The ref and cref functions are easy to implement. They just call the constructor, having deduced the type:
template <class T>
auto ref(T& r) { return reference_wrapper<T>(r); }
template <class T>
auto cref(T& r) { return reference_wrapper<const T>(r); }
You can see the full example on Coliru.
(The actual constructor of std::reference_wrapper, as shown on cppreference, is complicated because it needs to satisfy the requirement that the constructor will be SFINAE-disabled if the argument would match an rvalue reference better than an lvalue reference. For the purposes of your question, it doesn't seem necessary to elaborate on this detail further.)
The task is to create a single-argument function that forwards all types apart from one (Foo), which it converts (to Bar).
(Let us assume there exists a conversion from Foo to Bar).
Here is the usage scenario:
template<typename Args...>
void f( Args... args )
{
g( process<Args>(args)... );
}
(I've tried to extract/simplify it from the original context here. -- if I've made a mistake, please someone tell me!)
Here are two possible implementations:
template<typename T>
T&& process(T&& t) {
return std::forward<T>(t);
}
Bar process(Foo x) {
return Bar{x};
}
And...
template <typename T, typename U>
T&& process(U&& u) {
return std::forward<T>(std::forward<U>(u));
}
template <typename T>
Bar process(Foo x) {
return Bar{x};
}
I have it on good authority (here) that the second one is preferable.
However, I can't understand the given explanation. I think this is delving into some of the darkest corners of C++.
I think I'm missing machinery necessary to understand what's going on. Could someone explain in detail? If it is too much digging, could anyone recommend a resource for learning the necessary prerequisite concepts?
EDIT: I would like to add that in my particular case the function signature is going to match one of the typedef-s on this page. That is to say, every argument is going to be either PyObject* (with PyObject being an ordinary C struct) or some basic C type like const char*, int, float. So my guess is that the lightweight implementation may be most appropriate (I'm not a fan of over-generalising). But I am really interested in acquiring the right mindset to solve such problems as these.
I sense a minor misconception in your understanding of the use case you are facing.
First of all, this is a function template:
struct A
{
template <typename... Args>
void f(Args... args)
{
}
};
And this is not a function template:
template <typename... Args>
struct A
{
void f(Args... args)
{
}
};
In the former definition (with a function template) the argument type deduction takes place. In the latter, there is no type deduction.
You aren't using a function template. You're using a non-template member function from a class template, and for this particular member function its signature is fixed.
By defining your trap class like below:
template <typename T, T t>
struct trap;
template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{
static R call(Args... args);
};
and referring to its member function like below:
&trap<decltype(&Base::target), &Base::target>::call;
you end up with a pointer to a static non-template call function with a fixed signature, identical to the signature of the target function.
Now, that call function serves as an intermediate invoker. You will be calling the call function, and that function will call the target member function, passing its own arguments to initialize target's parameters, say:
template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{
static R call(Args... args)
{
return (get_base()->*t)(args...);
}
};
Suppose the target function used to instantiate the trap class template is defined as follows:
struct Base
{
int target(Noisy& a, Noisy b);
};
By instantiating the trap class you end up with the following call function:
// what the compiler *sees*
static int call(Noisy& a, Noisy b)
{
return get_base()->target(a, b);
}
Luckily, a is passed by reference, it is just forwarded and bound by the same kind of reference in the target's parameter. Unfortunately, this doesn't hold for the b object - no matter if the Noisy class is movable or not, you're making multiple copies of the b instance, since that one is passed by value:
the first one: when the call function is invoked itself from an external context.
the second one: to copy b instance when calling the target function from the body of call.
DEMO 1
This is somewhat inefficient: you could have saved at least one copy-constructor call, turning it into a move-constructor call if only you could turn the b instance into an xvalue:
static int call(Noisy& a, Noisy b)
{
return get_base()->target(a, std::move(b));
// ~~~~~~~~~~~^
}
Now it would call a move constructor instead for the second parameter.
So far so good, but that was done manually (std::move added knowing that it's safe to apply the move semantics). Now, the question is, how could the same functionality be applied when operating on a parameter pack?:
return get_base()->target(std::move(args)...); // WRONG!
You can't apply std::move call to each and every argument within the parameter pack. This would probably cause compiler errors if applied equally to all arguments.
DEMO 2
Fortunately, even though Args... is not a forwarding-reference, the std::forward helper function can be used instead. That is, depending on what the <T> type is in std::forward<T> (an lvalue reference or a non-lvalue-reference) the std::forward will behave differently:
for lvalue references (e.g. if T is Noisy&): the value category of the expression remains an lvalue (i.e. Noisy&).
for non-lvalue-references (e.g. if T is Noisy&& or a plain Noisy): the value category of the expression becomes an xvalue (i.e. Noisy&&).
Having that said, by defining the target function like below:
static R call(Args... args)
{
return (get_base()->*t)(std::forward<Args>(args)...);
}
you end up with:
static int call(Noisy& a, Noisy b)
{
// what the compiler *sees*
return get_base()->target(std::forward<Noisy&>(a), std::forward<Noisy>(b));
}
turning the value category of the expression involving b into an xvalue of b, which is Noisy&&. This lets the compiler pick the move constructor to initialize the second parameter of the target function, leaving a intact.
DEMO 3 (compare the output with DEMO 1)
Basically, this is what the std::forward is for. Usually, std::forward is used with a forwarding-reference, where T holds the type deduced according to the rules of type deduction for forwarding references. Note that it always requires from you to pass over the <T> part explicitly, since it will apply a different behavior depending on that type (not depending on the value category of its argument). Without the explicit type template argument <T>, std::forward would always deduce lvalue references for arguments referred to through their names (like when expanding the parameter pack).
Now, you wanted to additionally convert some of the arguments from one type to another, while forwarding all others. If you don't care about the trick with std::forwarding arguments from the parameter pack, and it's fine to always call a copy-constructor, then your version is OK:
template <typename T> // transparent function
T&& process(T&& t) {
return std::forward<T>(t);
}
Bar process(Foo x) { // overload for specific type of arguments
return Bar{x};
}
//...
get_base()->target(process(args)...);
DEMO 4
However, if you want to avoid the copy of that Noisy argument in the demo, you need to somehow combine std::forward call with the process call, and pass over the Args types, so that std::forward could apply proper behavior (turning into xvalues or not doing anything). I just gave you a simple example of how this could be implemented:
template <typename T, typename U>
T&& process(U&& u) {
return std::forward<T>(std::forward<U>(u));
}
template <typename T>
Bar process(Foo x) {
return Bar{x};
}
//...
get_base()->target(process<Args>(args)...);
But this is just one of the options. It can be simplified, rewritten, or reordered, so that std::forward is called before you call the process function (your version):
get_base()->target(process(std::forward<Args>(args))...);
DEMO 5 (compare the output with DEMO 4)
And it will work fine as well (that is, with your version). So the point is, the additional std::forward is just to optimize your code a little, and the provided idea was just one of the possible implementations of that functionality (as you can see, it brings about the same effect).
Would not be the first part of Version 2 sufficient? only:
template <typename T, typename U>
T&& process(U&& u) {
return std::forward<T>(std::forward<U>(u));
}
Given a usage case with an existing conversion (constructor for "Bar" from "Foo"), like:
struct Foo {
int x;
};
struct Bar {
int y;
Bar(Foo f) {
y = f.x;
}
};
int main() {
auto b = process<Bar>(Foo()); // b will become a "Bar"
auto i = process<int>(1.5f);
}
You are forced to specify the first template parameter (the type to convert to) anyway because the compiler cannot deduce it. So it knows what type you expect and will construct a temporary object of type "Bar" because there is a constructor.
So I have a std::map< std::string, boost::any > called OptionsMap and I want to create a function that takes any type (therefore the template) and stores it in the map.
Would the next code work?
template <typename T>
void Set(std::string optionName, T&& optionValue)
{
OptionsMap[optionName] = optionValue;
}
Typically, when a function template accepts a universal reference (i.e. an rvalue reference of a deduced type), you should cast the function parameter with forward so as to obtain a value of the same value category as was provided by the argument in the function call:
template <typename T>
void Set(std::string optionName, T&& optionValue)
{
OptionsMap[optionName] = std::forward<T>(optionValue);
// ^^^^^^^^^^^^^^^
}
The parameter variable optionValue itself is always an lvalue, so without the cast, you would be making copies of what should be moves. If the type is copyable, this will be less efficient than expected; if the type isn't copyable (e.g. unique_ptr), it's worse: your function now accepts an argument that it will subsequently fail to compile with.
Of course. Why wouldn’t it work?
boost::any::operator= accepts an argument of any data type satisfying ValueType.
I would just take by value and move it, for forward-compatibility when boost::any starts supporting move semantics.
template <typename T>
void Set(std::string optionName, T optionValue)
{
OptionsMap[optionName] = std::move(optionValue);
}
Passing an rvalue to this function will move it when it’s movable. That’s guaranteed by the standard.
are these functions equivalent?
template <class T>
void foo(T && t)
{
bar(std::forward<T>(t));
}
template <class T>
void foo2(T && t)
{
bar(std::forward<decltype(t)>(t));
}
template <class T>
void foo3(T && t)
{
bar(std::forward(t));
}
if they are, can I always use this macro for perfect forwarding?
#define MY_FORWARD(var) std::forward<decltype(var)>(var)
or just use
bar(std::forward(t));
I believe foo2 and foo3 are same, but I found people are always use forward like foo, is any reason to explicitly write the type?
I understand that T and T&& are two different types, but I think std::forward<T> and std::forward<T&&> always give the same result?
Edit:
the reason I want to use macro is I want to save some typing on following C++1y code, I have many similar code in different places
#define XLC_FORWARD_CAPTURE(var) var(std::forward<decltype(var)>(var))
#define XLC_MOVE_CAPTURE(var) var(std::move(var))
template <class T, class U>
auto foo(T && func, U && para )
{
auto val = // some calculation
return [XLC_FORWARD_CAPTURE(func),
XLC_FORWARD_CAPTURE(para),
XLC_MOVE_CAPTURE(val)](){
// some code use val
func(std::forward<U>(para));
};
}
Are these functions two equivalent?
Yes, they are equivalent. decltype(t) is the same as T&&, and when used with std::forward, there is no difference between T and T&&, regardless what T is.
Can I always use this macro for perfect forwarding?
Yes, you can. If you want to make your code unreadable and unmaintainable, then do so. But I strongly advise against it. On the one hand, you gain basically nothing from using this macro. And on the other hand, other developers have to take a look at the definition to understand it, and it can result in subtle errors. For example adding additional parentheses won't work:
MY_FORWARD((t))
In contrast, the form with decltype is perfectly valid. In particular, it is the preferred way of forwarding parameters from generic lambda expressions, because there are no explicit type parameters:
[](auto&& t) { foobar(std::forward<decltype(t)>(t)); }
I ignored the 3rd variant with std::forward(t), because it isn't valid.
Update: Regarding your example: You can use call-by-value instead of call-by-reference for the function template foo. Then you can use std::move instead of std::forward. This adds two additional moves to the code, but no additional copy operations. On the other hand, the code becomes much cleaner:
template <class T, class U>
auto foo(T func, U para)
{
auto val = // some calculation
return [func=std::move(func),para=std::move(para),val=std::move(val)] {
// some code use val
func(std::move(para));
};
}
The accepted answer does not solve the problem in title completely.
A macro argument preserves the type of the expression. A forwarding parameter in a template does not. This means t in foo2 (as a forwarding function parameter) has the type T&& (because this is the forwarding template parameter), but it can be something different when the macro is in other contexts. For example:
using T = int;
T a = 42;
T&& t(std::move(a));
foo(MY_FORWARD(t)); // Which foo is instantiated?
Note here t is not an xvalue, but an lvalue. With std::forward<T>(t), which is equivalent to std::forward<int>(t), t would be forwarded as an lvalue. However, with MY_FORWARD(t), which is equivalent to std::forward<int&&>(t), t would be forwarded as an xvalue. This contextual-dependent difference is sometime desired when you have to deal with some declared variables with rvalue reference types (not forwarding paramter even they may look like similar in syntax).
I have following code:
void myfunc()
{
}
template <typename T>
void check()
{
}
template <typename T>
void checkT (T)
{
check<T>();
}
and so if I have in main function a call to checkT(myfunc) then that compiles, but if I have check<myfunc>() that doesn't work although it directly calls the first version. Can you please explain why it is so? The error is
error: no matching function for call to 'check()'
Thanks!
This is because myfunc is a value expression, not a type. You could do
check<decltype(myfunc)>();
though, or equivalently:
check<void(void)>();
See it live on http://liveworkspace.org/code/2ANEre$0
PS. In reply to the comment, I sense a bit of confusion between the function formal parameter and a template type parameter. Make it more explicit by writing:
template <typename T>
void checkT (T somevalue)
{
check<T>(); // note: somevalue is never used!
}
In the first instance checkT(myfunc) it is able to deduce the type, checkT is really identical to checkT( T value ) and so you are passing in value and T is being deduced. In the second case you are not supplying a type you can alter it like so to work:
check<decltype(myfunc)>() ;
you are actually supplying a value where you need a type in this case void(void).
checkT(myfunc) works because myfunc is a value. But the second fails because it is not a type, which the template parameters require. For example,
void checkT(T)
is the same as
void checkT(T t)
so that means the function passed is an object of type T. That is, t is the object and T is the type. In the template parameters of check, it requires an explicit specification of the type, not the object. So thus passing in an object would raise a compilation error. Just like passing in the number 5 where the explicit type int is expected.
You can use it as a type by wrapping it in a decltype expression:
check<decltype(myfunc)>();
// ^^^^^^^^^^^^^^^^