If you want to bind a reference to a function f, you can use std::bind(f, std::ref(x)). In this case f takes a reference or makes a copy.
Now I have a function void g(T & t). I would like to bind the input argument to std::shared_ptr<T> mySharedPtr like this: std::bind(g, mySharedPtr). This would guarantee that mySharedPtr's data would have a lifetime at least as long as the bind. But since g takes a reference, this does not type-check.
Is there something similar to std::ref that takes a std::shared_ptr and dereferences it before passing it into g? If not, could I make one myself?
(If you give an answer using lambdas, please also include one without lambdas since my compiler does not support them.)
Edit: std::bind(g, std::ref(*mySharedPtr)) does not work since it loses the lifetime guarantee of the std::shared_ptr.
It seems you could create a deref() function which would create an object dereferencing something looking like a pointer upon conversion:
template <typename P>
class pointer_wrapper {
P ptr;
public:
pointer_wrapper(P p): ptr(p) {}
operator decltype(*std::declval<P>())&() {
return *ptr;
}
};
template <typename P>
pointer_wrapper<P> deref(P p) {
return p;
}
It may be better to make the conversion a member template to allow a few more conversions.
Related
I defined a class that receives an lambda function through constructor. The code is as follows. Why did the definition of t0 pass compilation after using the std::forward, and t1 incur an error?
#include <iostream>
template <typename Func>
class Test {
public:
Test(Func &&func) : m_func(std::forward<Func &&>(func)) {}
void Run() { m_func(); }
private:
Func &&m_func;
};
template <typename Func>
class Foo {
public:
Foo(Func &func) : m_func(func) {}
void Run() { m_func(); }
private:
Func &m_func;
};
int main() {
const auto print = []() { std::cout << "Hello" << std::endl; };
using Print = decltype(print);
Test<decltype(print)> t0(std::forward<Print&&>(print));
t0.Run();
Test<void()> t1(Print{});
t1.Run();
Foo<decltype(print)> t3(std::forward<Print&&>(print));
t3.Run();
Foo<void()> t4(Print{});
t4.Run();
}
[Update]
The definition of t1 should be as following. thx for #JaMiT.
Test<void(*)()> t1([]() { std::cout << "Hello" << std::endl; });
But I'm still confused about the definition of t0. If I deletes the std::forward, it incurs a compilation error.
[Update]
It works if I change the definition of t0 to Test<void (*)()> t0(print);. What's the difference between Test<decltype(print)> t0(print); that causes a compilation error?
Why did the definition of t0 pass compilation after using the std::forward,
Because that is how you declared the constructor of Test. The constructor takes as its parameter an rvalue reference to the template parameter. You explicitly provided decltype(print) as the template argument, so the constructor takes an rvalue of that type. There will be no copying (no pass by value), and an lvalue reference will not cut it. You must provide an rvalue.
By adding std::forward<Print&&>, you converted print to an rvalue. (It would have been simpler to add std::move instead. Rule of thumb: use std::forward when dealing with a "placeholder" type, such as a template parameter, and use std::move when dealing with a fixed type.)
Caution: After using std::forward<Print&&>(print) or std::move(print), you should treat print as uninitialized. That is, your initialization of t3 is a potential bug.
Another tweak that would make this compile is to specify decltype(print)& (with the ampersand at the end) as the template argument. When Func is an lvalue reference, Func&& collapses to Func, which means the constructor would take an lvalue reference instead of an rvalue reference. (Reference collapsing is a key component of forwarding references, on which perhaps you based your code? However, forwarding references would require the constructor to itself be a template.)
and t1 incur an error?
For t1, you specified the template argument as void(), which is the type of a function. Lambdas are objects, not functions, so there is a type mismatch.
On the other hand, a lambda with no captures (nothing inside the []) can implicitly convert to a pointer to a function. This is a place where confusion lurks, because functions also decay to pointers so people can get used to interchanging function types and pointer to function types. To specify a pointer to a function, use void(*)() instead of void().
Caution: Implicit conversions can wreak havoc when combined with references. Then again, you were already in the danger zone when you combined temporary objects (Print{}) with references. Your code would be safer if you changed the data member to Func m_func;. In addition to avoiding dangling references, this would be more efficient (less indirection) when storing a pointer-to-function.
template <typename Func>
class Test {
public:
// Constructor can still take a reference and forward it to the member.
Test(Func &&func) : m_func(std::forward<Func &&>(func)) {}
void Run() { m_func(); }
private:
Func m_func; // Not necessarily a reference
};
There are still potential issues (e.g. Func could be specified as a reference type), but at least this is safer. I choose to treat the remaining issues as out-of-scope for this question about syntax.
It works if I change the definition of t0 to Test<void (*)()> t0(print);.
This combines some concepts I presented earlier. The template argument is now a pointer to a function, so your lambda (print) will undergo an implicit conversion, similar to the t1 case. The result of an implicit conversion is an rvalue, which is what your constructor expects (no need to forward or move).
Caution: By "works", you really mean "compiles". The fact that you asked this question suggests you already know the following, but for the benefit of others: getting code to compile is a necessary step, but that by itself does not mean the code is correct and works as intended. Don't be satisfied when a tweak you do not understand makes your code compile – ask questions!
I want an object which can wrap a value symantic type and pretend that it is a reference.
Something like this:
int a = 20;
std::list<Wrap<int>> l1;
l1.push_back(a);
std::list<Wrap<int>> l2;
l2.push_back(a);
l2.front() = 10;
cout << l1.front() << endl; // output should be 10
While writing this question it occured to me that a shared_ptr might be what I want. However I am not sure if a pointer symantic object is what I am looking for. Perhaps there is no alternative in the standard library?
std::shared_ptr<int> a = std::make_shared(10);
std::list<std::shared_ptr<int>> l1;
l1.push_back(a);
std::list<std::shared_ptr<int>> l2;
l2.push_back(a);
*(l2.front()) = 20; // not exactly what I wanted to write
cout << *l1.front() << endl; // prints 10
I found std::reference_wrapper but this appears to be the opposite of what I want. It appears to permit a reference type to be used like a value type which is the reverse of what I wanted.
Any thoughts?
Proxy Object
As far as I know, there isn’t such a wrapper in the Standard Library. Fortunately though, you can implement one yourself rather easily.
How to start? Well, we’d like our Wrap<T> to be possibly indistinguishable from a T&. To achieve this, we can implement it as a proxy object. So, we’ll be making a class template storing a T& ref and implement operations one by one:
template<typename T>
struct Wrap
{
private:
T& ref;
public:
// ???
};
Construction
Let’s start with constructors. If we want Wrap<T> to behave like a T& it should be constructible from the same things that T& is constructible. Well then, what is a reference x constructible from?
A non-const lvalue reference like T& x = ...; needs to be constructed from an lvalue of type T. This means that it can be constructed from:
an object of type T
an object of a type derived from T
a different lvalue reference to T
an object convertible to T&
a function call returning T&
A const lvalue reference like const T& x = ...; can also be constructed from a braced-initializer-list or materialized from a temporary, however if we wanted to implement that, then we’d need to actually store a T inside of our class. As such, let’s focus on a non-const reference.
First, let’s implement a constructor from T& which will cover all of the cases shown above:
constexpr Wrap(T& t) noexcept :
ref{t}
{
}
The constructor is constexpr and noexcept because it can be. It is not explicit because we want to be able to use Wrap as transparently as possible.
We need to remember though, that a reference needs to be initializable from a different reference. Because we want our type to behave just like a builtin reference, we need to be able to
initialize a Wrap from a T& (already implemented above)
initialize a Wrap from a different Wrap
initialize a T& from a Wrap
To meet these criteria, we’ll need to implement a conversion operator to T&. If Wrap<T> will be implicitly convertible to T&, then assigning it to a builtin reference will work.
Actually, this:
int x;
Wrap w = x;
Wrap w2 = w;
will also work (ie. w2 will be Wrap<int> rather than a Wrap<Wrap<int>>) because the conversion operator takes precedence.
The implementation of the conversion operator looks like this:
constexpr operator T&() const noexcept
{
return ref;
}
Note that it is constexpr, noexcept and const, but not explicit (just like the constructor).
Miscelaneous operations
Now that we can construct our custom reference wrapper, we’d also like to be able to use it. The natural question is “what can you do with a reference”? Well, builtin references aren’t objects but merely aliases to existing objects. This means that taking the address of the reference actually returns the address of the referent or that you can access members through a reference.
All these things could be implemented, for example by overloading the arrow operator operator-> or the address-of operator operator&. For simplicity though, I will omit implementing these operations and focus only on the most important one: assignment.
Assignment
Firstly, we’d like to be able to assign a Wrap<T> to a T& or a T or basically anything that can be assigned a T. Fortunately, we already got that covered by having implemented the conversion operator.
Now we only need to implement assignment to Wrap<T>. We could be tempted to just write the operator like this:
constexpr T& operator=(const T& t)
{
ref = t;
return ref;
}
constexpr T& operator=(T&& t) noexcept
{
ref = std::move(t);
return ref;
}
Seems fine, right? We have a copy assignment operator and a noexcept move assignment operator. We return a reference as per custom.
Well, the problem is that this implementation is incomplete. The thing is that we don’t check
is T copy-assignable
if it is, then is it nothrow-copy-assignable
is T move-assignable
if it is, then is it nothrow-move-assignable
what is the return type of T’s assignment operator (it could be the customary T&, but it could also theoretically be anything else, like void)
does T have any other assignment operators
This is a lot of cases to cover. Fortunately, we can solve this all by making our assignment operator a template.
Let’s say that the operator will take an object of arbitrary type U as its argument. This will cover both the copy and move assignment operators and any other potential assignment operators. Then, let’s say that the return type of the function will be auto, to let the compiler deduce it. This gives us the following implementation:
template <typename U>
constexpr auto operator=(U u)
{
return (ref = u);
}
Unfortunately though, this implementation is still not complete.
We don’t know if the assignment is noexcept
We don’t distinguish copy assignment and move assignemnt and could potentially be making unnecessary copies.
Is the return type (auto) really correct?
To solve the first issue we can use a conditional noexcept. To check if the assignment operator is noexcept we can either use the type trait std::is_nothrow_assignable_v or the noexcept operator. I think that using the noexcept operator is both shorter and less error-prone, so let’s use that:
template <typename U>
constexpr auto operator=(U u) noexcept(noexcept(ref = u))
{
return (ref = u);
}
To solve the issue of distinguishing copies and moves, instead of taking a U u, we can take a forwarding reference U&& u, to let the compiler deal with all of this. We also need to remember about using std::forward:
template <typename U>
constexpr auto operator=(U&& u) noexcept(noexcept(ref = std::forward<U>(u)))
{
return (ref = std::forward<U>(u));
}
There is a bit of code duplication, but, unfortunately, it is inevitable, unless we’d use std::is_nothrow_assignable_v instead.
Finally, is the return type correct? Well, no. Because C++ is C++, parentheses around the returned value actually change its type (ie. return(x); is different from return x;). To return the correct type, we’ll actually also need to apply perfect forwarding to the returned type as well. We can do this by either using a trailing return type or a decltype(auto) return type. I will use decltype(auto) as it’s shorter and avoids duplicating the function body yet again:
template <typename U>
constexpr decltype(auto) operator=(U&& u) noexcept(noexcept(ref = std::forward<U>(u)))
{
return ref = std::forward<U>(u);
}
Conclusion
Now, finally, we have a complete implementation. To sum things up, here it is all together (godbolt):
template<typename T>
struct Wrap
{
private:
T& ref;
public:
constexpr Wrap(T& t) noexcept :
ref{t}
{
}
constexpr operator T&() const noexcept
{
return ref;
}
template <typename U>
constexpr decltype(auto) operator=(U&& u) noexcept(noexcept(ref = std::forward<U>(u)))
{
return ref = std::forward<U>(u);
}
};
That was quite a bit of C++ type theory to get through to write these 21 lines. Oh, by the way, did I mention value categories...
I'm used to pass lambda functions (and other callables) to template functions -- and use them -- as follows
template <typename F>
auto foo (F && f)
{
// ...
auto x = std::forward<F>(f)(/* some arguments */);
// ...
}
I mean: I'm used to pass them through a forwarding reference and call them passing through std::forward.
Another Stack Overflow user argue (see comments to this answer) that this, calling the functional two or more time, it's dangerous because it's semantically invalid and potentially dangerous (and maybe also Undefined Behavior) when the function is called with a r-value reference.
I've partially misunderstand what he means (my fault) but the remaining doubt is if the following bar() function (with an indubitable multiple std::forward over the same object) it's correct code or it's (maybe only potentially) dangerous.
template <typename F>
auto bar (F && f)
{
using A = typename decltype(std::function{std::forward<F>(f)})::result_type;
std::vector<A> vect;
for ( auto i { 0u }; i < 10u ; ++i )
vect.push_back(std::forward<F>(f)());
return vect;
}
Forward is just a conditional move.
Therefore, to forward the same thing multiple times is, generally speaking, as dangerous as moving from it multiple times.
Unevaluated forwards don't move anything, so those don't count.
Routing through std::function adds a wrinkle: that deduction only works on function pointers and on function objects with a single function call operator that is not && qualified. For these, rvalue and lvalue invocation are always equivalent if both compiles.
I'd say the general rule applies in this case. You're not supposed to do anything with a variable after it was moved/forwarded from, except maybe assigning to it.
Thus...
How do correctly use a callable passed through forwarding reference?
Only forward if you're sure it won't be called again (i.e. on last call, if at all).
If it's never called more than once, there is no reason to not forward.
As for why your snippet could be dangerous, consider following functor:
template <typename T>
struct foo
{
T value;
const T &operator()() const & {return value;}
T &&operator()() && {return std::move(value);}
};
As an optimization, operator() when called on an rvalue allows caller to move from value.
Now, your template wouldn't compile if given this functor (because, as T.C. said, std::function wouldn't be able to determine return type in this case).
But if we changed it a bit:
template <typename A, typename F>
auto bar (F && f)
{
std::vector<A> vect;
for ( auto i { 0u }; i < 10u ; ++i )
vect.push_back(std::forward<F>(f)());
return vect;
}
then it would break spectacularly when given this functor.
If you're either going to just forward the callable to another place or simply call the callable exactly once, I would argue that using std::forward is the correct thing to do in general. As explained here, this will sort of preserve the value category of the callable and allow the "correct" version of a potentially overloaded function call operator to be called.
The problem in the original thread was that the callable was being called in a loop, thus potentially invoked more than once. The concrete example from the other thread was
template <typename F>
auto map(F&& f) const
{
using output_element_type = decltype(f(std::declval<T>()));
auto sequence = std::make_unique<Sequence<output_element_type>>();
for (const T& element : *this)
sequence->push(f(element));
return sequence;
}
Here, I believe that calling std::forward<F>(f)(element) instead of f(element), i.e.,
template <typename F>
auto map(F&& f) const
{
using output_element_type = decltype(std::forward<F>(f)(std::declval<T>()));
auto sequence = std::make_unique<Sequence<output_element_type>>();
for (const T& element : *this)
sequence->push(std::forward<F>(f)(element));
return sequence;
}
would be potentially problematic. As far as my understanding goes, the defining characteristic of an rvalue is that it cannot explicitly be referred to. In particular, there is naturally no way for the same prvalue to be used in an expression more than once (at least I can't think of one). Furthermore, as far as my understanding goes, if you're using std::move or std::forward or whatever other way to obtain an xvalue, even on the same original object, the result will be a new xvalue every time. Thus, there also cannot possibly be a way to refer to the same xvalue more than once. Since the same rvalue cannot be used more than once, I would argue (see also comments underneath this answer) that it would generally be a valid thing for an overloaded function call operator to do something that can only be done once in case the call happens on an rvalue, for example:
class MyFancyCallable
{
public:
void operator () & { /* do some stuff */ }
void operator () && { /* do some stuff in a special way that can only be done once */ }
};
The implementation of MyFancyCallable may assume that a call that would pick the &&-qualified version cannot possibly happen more than once (on the given object). Thus, I would consider forwarding the same callable into more than one call to be semantically broken.
Of course, technically, there is no universal definition of what it actually means to forward or move an object. In the end, it's really up to the implementation of the particular types involved to assign meaning there. Thus, you may simply specify as part of your interface that potential callables passed to your algorithm must be able to deal with being called multiple times on an rvalue that refers to the same object. However, doing so pretty much goes against all the conventions for how the rvalue reference mechanism is generally used in C++, and I don't really see what there possibly would be to be gained from doing this…
I have a library function (not under my control here) which take an r value reference to the movable and copyable type Bar:
void foo(Bar&& b);
In my own code, I sometimes need to give it a copy of an existing value, such as
const auto b = getBar();
foo(mk_copy(b));
b.baz();
This is what comes to mind,
template<typename T> auto mk_copy(T val){return val;}
Is there a standard way to do this, or a more common pattern? Perhaps even
template<typename T> auto mk_copy(T&& val){return std::forward<T>(val);}
Or, as pscill points out just writing the name of the class again,
foo(Bar(b));
but I prefer not to repeat type names.
For the built-in types the prefix + plays the role of “make a copy”:
void foo( char&& ) {}
void bar( double*&& ) {}
auto main() -> int
{
char x{};
foo( +x );
double* p{};
bar( +p );
}
Still, it would probably be confusing to readers of the code if you applied prefix + to some other type, and a general prefix operator+ template might end up in conflict with some class' own prefix operator+.
So, I suggest using the now apparent naming convention for makers, namely a make prefix.
Then it can look like this:
template< class Type >
auto make_copy( Type const& o ) -> Type { return o; }
Your first proposed solution,
template<typename T> auto mk_copy(T val){return val;}
suffers from potentially copying the value twice: first copying to the by-value argument, and then copying to the function result.
This is not a problem for a movable type such as a standard library container, because the return type copying will reduce to a move. But it can be a problem for largish non-movable type, as can occur in legacy code.
The second proposed solution,
template<typename T> auto mk_copy(T&& val){return std::forward<T>(val);}
takes the argument by forwarding reference (a.k.a. universal reference), and then deduces the return type from a re-creation of the argument type. The return type will always be a non-reference, since that's what plain auto deduces, so this is technically correct. But it's needlessly complicated.
There is no standard mechanism, but if you want one, your examples aren't very good. The first mk_copy copies T twice (or copies and moves). The second one seems very confusing as to what it's trying to do.
The obvious way is to simply take a const T&, like you normally would:
template<typename T> T mk_copy(const T &val){return val;}
I think you'd better just define that mk_copy method, or add one more declaration:
auto b_copy = b;
foo(std::move(b_copy));
These are clearer to the readers.
Just to demonstrate the possibilities, you could use decltype to get the type:
foo(std::decay_t<decltype(b)>{b});
or you could get the same effect with lambdas:
foo([&]{return b;}());
or tuples:
foo(std::get<0>(std::make_tuple(b)));
or pairs:
foo(std::make_pair(b, 0).first);
Here's a very simple example:
#include <iostream>
template<typename T>
void DoubleMe(T x) {
x += x;
}
int main()
{
int a = 10;
DoubleMe(a);
std::cout << a; //displays 10 not 20!
}
In cases like this, am I forced to use 'T&' in the function argument instead? Cuz I have read in some tutorials that templates can correctly deduce the appropriate data type, including T*, T[ ], or T& by just defining a simple 'T' before the variable. Help?
You can indeed correctly deduce reference types with plain T. Unfortunately, that does not mean what you think it means.
Given
template <typename T> struct S { };
template <typename T> void f(S<T>) { }
int main() { f(S<int&>{}); }
the type argument for f is correctly deduced as int&.
The problem is that in your case, deducing T as int produces a perfectly valid function already. Perhaps a slight oversimplification, but type deduction produces the simplest T that makes the call work. In your case, T = int makes the call work. Not the way you want it to work, but the compiler can't know that. T = int & would also make the call work, but it's not the simplest T that makes it work.
Maybe this will help you to see it the way the compiler does (apologies to any language lawyers if I am oversimplifying):
In this example, the compiler must infer the type of T to be the type that makes the function declaration legal with the least amount of deduction. Since a T can usually be copy-constructed directly from a const T& (which implies that it can also be copy-constructed from a T&), your function will take a copy.
template<class T>
void foo(T value);
In this example T must be the type of the object thing ref refers to - and since references cannot refer to references, T must be a (possibly const, possibly volatile) type.
template<class T>
void foo(T& ref);
In this example, ref must be referring to a const (possibly volatile) object of type T:
template<class T>
void foo(const T& ref);
In this example, ref may either be a reference or an r-value reference. It's known as a universal reference. You're actually writing two functions in one and it's often the most efficient way to handle the case where you are taking ownership of ref.
template<class T>
void foo(T&& ref);
// called like this:
foo(Bar()); // means ref will be a Bar&&
// called like this:
Bar b;
foo(b); // means ref will be a Bar&
// called like this:
const Bar b;
foo(b); // means ref will be a const Bar&
In summary:
void foo(T value) means I will make a copy of whatever you give me.
void foo(T& value) means I wont make a copy but I may modify your value. You may not give me a temporary.
void foo(const T& value) means I wont make a copy and I cannot modify your copy. You may give me a temporary.
void foo(const T&& value) means I may steal or modify the contents of your value, even if it's a temporary.
Yes, to get the effect you want here, you must add the ampersand.
As you write, templates can correctly deduce data types. However, they cann deduce intent. In this case, the type you pass it is an integer, and it correctly instantiates an integer function that internally doubles the argument passed to it by value. The fact that you meant the function to have a side effect, is not something the compiler can guess.
If you want the function to pass the argument by value, you need to return the value with the same argument type.
T DoubleMe(T x) {
return x + x;
}