C++ template overloading - wrong function called - c++

template<typename T> T* Push(T* ptr);
template<typename T> T* Push(T& ref);
template<typename T, typename T1> T* Push(T1&& ref);
I have
int i = 0;
Push<int>(i);
But the compiler calls it ambiguous. How is that ambiguous? The second function is clearly the preferred match since it's more specialized. Especially since the T1&& won't bind to an lvalue unless I explicitly forward/move it.
Sorry - i is an int. Otherwise, the question would make no sense, and I thought people would infer it since it's normally the loop iterator.

If i is an int, then the first isn't viable. Last two remain. Then, for deduction of i, the second and the third both yield the same function types for overload resolution (both int& as parameter). So you have to rely on partial ordering.
However, partial ordering can't tell them apart. For a function call partial ordering context, only the parameters are used to determine an order (and the return type in your example is not considered), and any reference modifier is peeled off from them. So you will succeed deducing the parameter type from one against the other in both direction - both parameter types will be at least as specialized as the other parameters respectively. And neither has const applied, so neither is more specialized than the other.
There is an issue report placeholder that aims at clarifying anything related to rvalue/lvalue reference difficulties during partial ordering. See this usenet question for details.
If any of the two should be more specialized, i would say that it should the first one. After all, it accepts less arguments than the other one (the other one being a potential perfect forwarder).
Especially since the T1&& won't bind to an lvalue unless I explicitly forward/move it.
Actually, it will accept anything. Having a parameter of type T&& in a template will switch to the "perfect-forwarding-deduction-mode", which will deduce T to the type of the argument if it's an rvalue, and add a lvalue-reference modifier to the type of T if it's an lvalue. So if the argument is an lvalue, the resulting parameter type is T& && collapsed to T&, which accepts lvalues fine (just like in your case).
On a second look, what you seem to be trying to do is to overload a function for taking objects by moving them. But this won't work because of the special deduction done for T&& (see below). Just erase the first function and write your code as
template<typename T, typename T1> T* Push(T1&& ref) {
/* for lvalues, T1 is U& and rvalues it is U, with U being the
* argument type. */
T t1(std::forward<T1>(ref));
/* whatever needs to be done ... */
}
This will move-construct t1 if the argument was an rvalue, and copy ref if the argument was an lvalue or if T doesn't have a move constructor. This is just an illustration, it may not be what you actually should do depending on your real use-case. I'm also not sure why you have two template parameter types here. I propose to get rid of the T, and say typename remove_reference<T1>::type * for the return type, instead. So that you can gain from argument deduction.

Related

Why does a template argument of type T& resolves to T?

Here for example, b is of type int& but f(b) resolves to f(int):
#include <type_traits>
template <typename T>
void f(T arg) {
static_assert(std::is_reference<T>::value); // fails
}
void g() {
int a = 5;
int& b = a;
f(b);
}
I know the standard dictates it - I'm asking, why? What goes wrong (or - becomes 'surprising') if the reference isn't dropped?
There are two things at play here.
What if you, as the author of f, wants to write a template function where the user is required to copy/move a parameter into the function?
In non-template code, that prototype would look like this: void f(SomeType st);. Any caller of f has no choice but to copy/move into the parameter. Whether they have an object, a reference to an object, or something else. st shall be an object separate and distinct from the rest.
Template argument deduction is intended to look like the non-template version where possible. So if you have template<typename T> void f(T t);, and you call it with f(some_object), that should work exactly like the untemplated version.
The other thing at play here is that reference variables are supposed to just be a different name for some object. That is, a and b, should, all things being equal, behave identically. So f(a) ought to do the same thing as f(b).
The rules of template argument deduction favor both of these. It keeps references behaving exactly like the object, and it allows the template function to behave like an equivalently-defined non-template version.
If you want a reference type, you must forgo template argument deduction and specify it directly: f<decltype((b))>(b). Note the use of double-parentheses here; that's important for getting decltype to be a reference.
According to the rules of the language, f(b) is not calling f with an expression of type int&. It is calling f with an lvalue of type int. The same would also occur if you did f(a).
In general, when a reference variable is mentioned by name, it is an expression that is an lvalue of the referenced type. The fact that the variable itself is a reference is not visible to the type system.
Thus, f never deduces T to have reference type. From f's point of view, the argument is never actually a reference.
What goes wrong (or - becomes 'surprising') if the reference isn't dropped?
Consider following function:
template <typename T>
void f(T arg) {
something = std::move(arg);
// ...
f(lvalue); // copies
f(str::move(lvalue)); // moves
The intention is to copy from an lvalue, and move from an rvalue.
If T deduced to a reference, then lvalue argument would be moved from, which is in this case undesirable.
I don't want to copy the argument.
If you're writing the function, then specify a reference parameter using & symbol, and not an object parameter. That way the argument can never be copied into the call (you can still copy inside the function).
If you're calling a function that accepts an object parameter, then pass an rvalue and not an lvalue. That way you will copy only if the move is a copy, and there is no copy elision involved.
Doesn't make sense to me that the template type deduction rules decide for me that I do
You decided to use T. You should instead decide to use T&, T&& or const T& if you want a reference.

What is the purpose of std::forward()'s rvalue reference overload?

I'm experimenting with Perfect Forwarding and I found that
std::forward() needs two overloads:
Overload nr. 1:
template <typename T>
inline T&& forward(typename
std::remove_reference<T>::type& t) noexcept
{
return static_cast<T&&>(t);
}
Overload nr.2:
template <typename T>
inline T&& forward(typename
std::remove_reference<T>::type&& t) noexcept
{
static_assert(!std::is_lvalue_reference<T>::value,
"Can not forward an rvalue as an lvalue.");
return static_cast<T&&>(t);
}
Now a typical scenario for Perfect Forwarding is something like
template <typename T>
void wrapper(T&& e)
{
wrapped(forward<T>(e));
}
Of course you know that when wrapper() is instantiated, T depends on whether the argument passed to it is an lvalue or an rvalue. If it's an lvalue of type U, T is deduced to U&. If it's an rvalue, T is deduced to U.
In any case - in the scope of wrapper() - e is an lvalue, therefore it always uses the first overload of std::forward().
Now my question:
What is a valid scenario in which the 2nd overload is used (and is needed)?
The design rationale for forward is discussed in great detail in N2951.
This document lays out 6 use cases:
A. Should forward an lvalue as an lvalue. All implementations pass
this test. But this is not the classic perfect forwarding pattern. The
purpose of this test is to show that implementation 2 fails in its
stated goal of preventing all use cases except perfect forwarding.
B. Should forward an rvalue as an rvalue. Like use case A, this is
an identity transformation and this presents a motivating example
where the identity transformation is needed.
C. Should not forward an rvalue as an lvalue. This use case
demonstrates a dangerous situation of accidentally creating a dangling
reference.
D. Should forward less cv-qualified expressions to more
cv-qualified expressions. A motivating use case involving the
addition of const during the forward.
E. Should forward expressions of derived type to an accessible,
unambiguous base type. A motivating use case involving forwarding a
derived type to a base type.
F. Should not forward arbitrary type conversions. This use case
demonstrates how arbitrary conversions within a forward lead to
dangling reference run time errors.
The second overload enables cases B and C.
The paper goes on to provide examples of each use case, which are too lengthy to be repeated here.
Update
I've just run the "solution" of just the first overload through these 6 use cases, and this exercise shows that the second overload also enables use case F: Should not forward arbitrary type conversions.

Deduced conflicting types for universal reference and pointer to member

I want a function like this:
template<typename C, typename T>
void foo(C &&aclass, T (C::*const memberFunc)(unsigned)) {
}
The parameters are (in words because C/C++ type syntax is mental):
A universal reference to a class, e.g. MyClass.
A const pointer to a member function of MyClass that takes an unsigned int and returns T.
This sort of works, however if I call it with an l-value reference as the first parameter I get an error like:
candidate template ignored: deduced conflicting types for parameter 'C' ('MyClass &' vs. 'MyClass')
As far as I understand it, it is deducing C from the first and second parameters, but comes up with different deductions and gets confused.
According to this answer you can make it only do deduction on the first parameter, and somehow use the typename keyword on the second parameter. But I can't work out the syntax to do this when I do want it to deduce one of the types in the parameter (T), but not the other (C).
This answer is also helpful but they solve it by just not using references for C at all, which in that case is equally efficient, but not in mine.
Is this possible?
With lvalues C will be deduced to be an lvalue-reference type (i.e. MyClass & for your case) for the 1st parameter, which is the expected behavior of forwarding reference; you can remove the reference-ness via std::remove_reference when using C in the 2nd parameter, e.g.
template<typename C, typename T>
void foo(C &&aclass, T (std::remove_reference_t<C>::*const memberFunc)(unsigned)) {
}
And as #Quentin pointed, using of std::remove_reference also introduces non-deduced context, that would prevent C from being deduced from the 2nd parameter.
Actually I just found that having a universal reference overload forward it to an l-value reference version works. Not particularly elegant though; I feel like there should be a better way.
template<typename C, typename T>
void foo(C &aclass, T (C::*const memberFunc)(unsigned)) {
// Code goes here.
}
template<typename C, typename T>
void foo(C &&aclass, T (C::*const memberFunc)(unsigned)) {
foo(aclass, memberFunc);
}

Difference between add_lvalue_reference_t<T> and T&

Suppose you have a template argument T.
What are the differences between
add_cv_t<T> and const volatile T
add_const_t<T> and const T
add_volatile_t<T> and volatile T
add_lvalue_reference_t<T> and T&
add_rvalue_reference_t<T> and T&&
add_pointer_t<T> and T*?
Why should I use add_rvalue_reference_t<T> instead of T&& for example. Are there any rules when to choose which?
add_cv_t<T> and const volatile T
add_const_t<T> and const T
add_volatile_t<T> and volatile T
No difference; the definition of add_const<T>::type is just T const, for example.
add_lvalue_reference_t<T> and T&
add_rvalue_reference_t<T> and T&&
T& and T&& are ill-formed when T is cv void, but these templates are well-formed, just giving the original type back.
add_pointer_t<T> and T*?
add_pointer_t<T> is equivalent to std::remove_reference<T>::type*. That is, if T is a reference type, it gives a pointer to the referenced type. On the other hand, T* will be ill-formed since you cannot have a pointer to a reference.
Which should you use?
In general, the alias templates can be used to prevent deduction of T. Of course, that means that if you want deduction, you should avoid them.
The alias templates can be used as template template arguments to a template that takes a type transformation as a parameter.
The alias templates that differ in behaviour from alternatives like T* are useful in generic code since they "do the right thing". For example, if T is deduced from an argument of type T&&, then T* does the wrong thing when the argument is an lvalue, since it tries to declare a pointer to an lvalue reference. But std::add_pointer_t<T> will give a pointer to the actual type of the argument.
According to what I see in STL source:
add_cv_t<T> and const volatile T- no difference
add_const_t<T> and const T - no difference
add_volatile_t<T> and volatile T - no difference
add_lvalue_reference_t<T> and T& - there is difference for example if T is non referenceable type void. add_lvalue_reference_t<void>::type = void and void& = compile-time error
add_rvalue_reference_t<T> and T&& - the same as above
add_pointer_t<T> and T* - difference when T is reference, because there is no such thing as pointer to reference. add_pointer_t<T> is equivalent to std::remove_reference<T>::type*
In most cases, std::add_rvalue_reference_t<T> is equivalent to T&&. However, reference collapsing rules and the-rules-that-dictate-which-types-are-referenceable may have your code misbehave if not taked into account.
There are, however, some cases where the type static member type will be different due to T being a non-referenceable type. For example std::add_rvalue_reference_t<void> resolves to void, and (taking another template you mentioned as an example) std::add_pointer_t<T&> resolves to T* (if you want to invoke chaos, the required ritual is std::add_pointer_t<std::add_rvalue_reference_t<void>> :))
Respecting to uses, it may be used as a template template parameter to do some funky black magic. Anyway, stuff like std::is_rvalue_reference_t<T> or std::remove_reference_t<T> is usually more commonly used when manipulating the type's reference attributes.

Type deduction of function template parameters

I have some questions concerning function templates.
My plan was to build a wrapper which derives from a user-defined class and
not only exports the public functions of that class but also its constructors.
So I decided I would use multiple constructor templates (which I presume work exactly
the same as function templates) with 1 to n parameters to satisfy most constructors needs.
These would than simply call the constructor and do something else afterwards, like
this:
template <class T>
class Wrapper : public T
{
public:
template <class U>
Wrapper(U &u) : T(u) { doSomething(); }
template <class U, class V>
Wrapper(U &u, V &v) : T(u,v) { doSomething(); }
...
};
My intent is to register the instance within the Wrapper-Ctor somewhere else and,
from that point on, it can receive calls to virtual functions defined in T.
I had to use the reference operator in the code above, in order to guarantee that
my Wrapper-Ctor does not have any side-effects on the parameters that were passed
(copy-construction).
To my surprise this always worked, except for temporaries, which is the reason why
I am confused about the types that are inferred by the compiler in this situation.
To simplify the situation I tried to do something similiar via a template function:
template <class T>
void foo(T &t)
{
int x = ""; // intentional error
}
Calling the function like this:
std::string a;
std::string &b = a;
foo(b);
To my surprise the compiler denotes [T = std::string] in its error message.
I would have expected for this to be [T = std::string&], which would have caused
passing a reference-to-reference, which is invalid.
So, why does the compiler deduce a value-type in this situation?
Is it even possible to create a Wrapper-Ctor that does what I want, does not
have any side-effects on the parameters and also accepts temporaries?
Thanks alot!
It looks like the C++ spec explicitly states that this is the intended behavior. Specifically, if you have a template function that takes in a parameter P that depends on a template type argument, if P is a reference, then the underlying type of the reference, rather than the reference type, is used to determine what type should be used for P (see ยง14.8.2.1/2). Moreover, this same section says that const and volatile qualifiers are ignored during this step, so the constness can be inferred automatically.
It is not possible in C++03 to provide such a thing without manually overloading for every combination of const and non-const parameters.
No expression ever has reference type. Therefor, when argument deduction deduces against the argument expression type, it cannot make a distinction between a and b because the arguments a and b both have the same type.
Refer to [expr]p5 in the spec
If an expression initially has the type "reference to T" (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis.
Somewhat late, but since I don't think this was answered completely...
For template parameter deduction, see the previous answers.
For your problem with temporaries, make the parameters const references (as in Wrapper(const U&)).
The thing is, temporaries are rvalues. The standard states that non-const references can only be bound to lvalues. Therefore, a standards compliant compiler won't let you pass temporaries(rvalues) as arguments to non-const reference parameters. (This doesn't have anything to do with templates in particular, it's a general rule).
This is to the best of my knowledge, so take it with a bit of scepticism.