Function overload resolution with nullptr as argument - c++

Consider the code below. Although both overloads of fun accept pointers, passing nullptr to fun does not result in any compilation error. Whereas, the very similar function bun fails to compile. When I print the the types of the argument i using typeid(i).name() (after modifying the code just to get this printed) I get the same type, simply int*. What is the rule that resolves the ambiguity in fun case, but fails for bun? Thanks in advance!
#include <iostream>
struct Foo {
int sth;
};
template< class U>
void fun(decltype(U::sth)* i){
std::cout << "1" << std::endl;
}
template< class U>
void fun(U* i){
std::cout << "2" << std::endl;
}
void bun(decltype(Foo::sth)* i){
std::cout << "3" << std::endl;
}
void bun(Foo* i){
std::cout << "4" << std::endl;
}
int main ( )
{
fun<Foo>(nullptr);
// bun(nullptr); --> call of overloaded 'bun(std::nullptr_t)' is ambiguous
return 0;
}
-----------------------
output : 1

Well, in fact, GCC accepts your code, but Clang does not. So it is not, at first, obvious whether the call is ambiguous.
You ask what rule resolves the ambiguity in the fun case; GCC evidently thinks that there is such a rule. I imagine the rule that GCC is applying is the rule [over.match.best]/1.7 that prefers a more specialized function template over a less specialized one.
The procedure for determining which function template is more specialized than the other is described in [temp.func.order] and is explained thoroughly in this SO answer. However, you will notice that when attempting to apply this procedure to the two overloads of fun as in this question, we run into the problem that the unique synthesized type that needs to be substituted for U in the first overload would need to have a member named sth, and the nature of this member is not specified, and although it may be clear to a human that deduction in the second fun overload must succeed regardless of what sth's type is, the compiler may not be able to prove it.
This is CWG 1157. As this issue is still open with no proposed resolution, I have no insight into whether WG21 intends for this overload resolution to succeed or not.

Related

std::variant converting constructor doesn't handle const volatile qualifiers

The code below:
int i = 1;
const int i_c = 2;
volatile int i_v = 3;
const volatile int i_cv = 4;
typedef std::variant<int, const int, volatile int, const volatile int> TVariant;
TVariant var (i );
TVariant var_c (i_c );
TVariant var_v (i_v );
TVariant var_cv(i_cv);
std::cerr << std::boolalpha;
std::cerr << std::holds_alternative< int>(var ) << std::endl;
std::cerr << std::holds_alternative<const int>(var_c ) << std::endl;
std::cerr << std::holds_alternative< volatile int>(var_v ) << std::endl;
std::cerr << std::holds_alternative<const volatile int>(var_cv) << std::endl;
std::cerr << var .index() << std::endl;
std::cerr << var_c .index() << std::endl;
std::cerr << var_v .index() << std::endl;
std::cerr << var_cv.index() << std::endl;
outputs:
true
false
false
false
0
0
0
0
coliru
And so std::variant converting constructor doesn't take into account const volatile qualifier of the converting-from type. Is it expected behavior?
Information about converting constructor from cppreference.com
Constructs a variant holding the alternative type T_j that would be selected by overload resolution for the expression F(std::forward<T>(t)) if there was an overload of imaginary function F(T_i) for every T_i from Types...
The problem is that in the case above the overload set of such imaginary function is ambiguous:
void F( int) {}
void F(const int) {}
void F( volatile int) {}
void F(const volatile int) {}
coliru
cppreference.com says nothing about this case. Does the standard specify this?
I'm making my own implementation of std::variant class. My implementation of converting constructor is based on this idea. And the result is the same as shown above (the first suitable alternative is selected, even though there are others). libstdc++ probably implements it in the same way, because it also selects the first suitable alternative. But I'm still wondering if this is correct behavior.
Yeah, this is just how functions work when you pass by value.
The function void foo(int) and the function void foo(const int) and the function void foo(volatile int) and the function void foo(const volatile int) are all the same function.
By extension, there is no distinction for your variant's converting constructor to make, and no meaningful way to use a variant whose alternatives differ only in their top-level cv-qualifier.
(Well, okay, you can emplace with an explicit template argument, as Marek shows, but why? To what end?)
[dcl.fct/5] [..] After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. [..]
Note that you are creating copy of value. This means that const and volatile modifiers can be safely discarded. That is why template always deduces int.
You can force specific type using emplace.
See demo https://coliru.stacked-crooked.com/a/4dd054dc4fa9bb9a
My reading of the standard is that the code should be ill-formed due to ambiguity. It surprises me that both libstdc++ and libc++ appear to allow it.
Here's what [variant.ctor]/12 says:
Let T_j be a type that is determined as follows: build an imaginary function FUN(T_i) for each alternative type T_i. The overload FUN(T_j) selected by overload resolution for the expression FUN(std::forward<T>(t)) defines the alternative T_j which is the type of the contained value after construction.
So four functions are created: initially FUN(int), FUN(const int), FUN(volatile int), and FUN(const volatile int). These are all equivalent signatures, so they could not be overloaded with each other. This paragraph does not really specify what should happen if the overload set cannot actually be built. However, there is a note that strongly implies a particular interpretation:
[ Note:
variant<string, string> v("abc");
is ill-formed, as both alternative types have an equally viable constructor for the argument. —end note]
This note is basically saying that overload resolution cannot distinguish between string and string. In order for that to happen, overload resolution must be done even though the signatures are the same. The two FUN(string)s are not collapsed into a single function.
Note that overload resolution is allowed to consider overloads with identical signatures due to templates. For example:
template <class T> struct Id1 { using type = T; };
template <class T> struct Id2 { using type = T; };
template <class T> void f(typename Id1<T>::type x);
template <class T> void f(typename Id2<T>::type x);
// ...
f<int>(0); // ambiguous
Here, there are two identical signatures of f, and both are submitted to overload resolution but neither is better than the other.
Going back to the Standard's example, it seems that the prescription is to apply the overload resolution procedure even if some of the overloads could not be overloaded with each other as ordinary function declarations. (If you want, imagine that they are all instantiated from templates.) Then, if that overload resolution is ambiguous, the std::variant converting constructor call is ill-formed.
The note does not say that the variant<string, string> example was ill-formed because the type selected by overload resolution occurs twice in the list of alternatives. It says that the overload resolution itself was ambiguous (because the two types had equally viable constructors). This distinction is important. If this example were rejected after the overload resolution stage, an argument could be made that your code is well-formed since the top-level cv-qualifiers would be deleted from the parameter types, making all four overloads FUN(int) so that T_j = int. But since the note suggests a failure during overload resolution, that means your example is ambiguous (as the 4 signatures are equivalent) and this must be diagnosed.

Why doew GCC compiles function overloaded with value, rvalue and lvalue parameter?

I don't understand why this code compiles:
#include <iostream>
class T {
};
void fun(T) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void fun(const T&) { // Why does this compile?
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void fun(const T&&) { // Why does this compile?
}
int main() {
return 0;
}
The overloads T and const T& are always conflicting, so I don't understand why GCC compiles it.
I have readen that like "a parameter of category value can't be overloaded by a parameter of rvalue or lvalue".
If the overload with T and const T&& works, does it mean that it will be impossible to pass a rvalue to this function in any way, because any call would be ambiguous ? Or is it a way to disambiguiate the call ?
GCC Version: gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
__cplusplus = 201103
The overloads are indeed conflicting (ambiguous) under ordinary overload resolution, but they are still resolvable by explicit means
T a;
static_cast<void(*)(T)>(fun)(a); // calls `T` version
static_cast<void(*)(const T &)>(fun)(a); // calls `const T &` version
although I don't immediately see any use case for it.
As for const T && overload - it has some narrow applicability if you for some reason want to prohibit calling your const T & function with non-lvalue arguments
void fun(const T &) {}
void fun(const T &&) = delete;
int main()
{
T t;
fun(t); // OK
fun(T()); // Error
}
See, for example, how it is done for std::ref, std::cref.
I'll assume that you have defined the type T somewhere preceding this code snippet. Otherwise, of course, the code would not compile.
It's not quite true that if one overload takes T and one takes const T&, then overload resolution can never select one of them over the other. For example, if the argument has type volatile T, then the overload taking T must be selected over the one taking const T&. This corner case aside, though, these functions are always individually callable by bypassing overload resolution entirely:
static_cast<void(*)(T)>(fun)(x); // calls void fun(T) on x
It's not the compiler's job to prevent you from declaring functions that pose issues for overload resolution. A good compiler might, perhaps, warn you; but then again, I don't think such a warning is necessary, since almost no programmer would write code like this, other than as an experiment.

call of overloaded is ambiguous because of references

I have this code, which compiles fine:
void foo(int x){std::cout << "value copy" << std::endl;} // foo(5) or foo(n)
void foo(int &x){std::cout << "lvalue ref" << std::endl;} // foo(n) only
void foo(int &&x){std::cout << "rvalue ref" << std::endl;} // foo(5) only
but since i have referenced versions, it's ambiguous.
how are you meant to use this functionality? i thought the compiler would've gave me an error.
i know we can cast functions, but in that case it'd seem pointless.
you'd might as well call them fooL and fooR if you're just gonna cast right?
During overload resolution, when selecting the best viable function, the compiler will select the overload that has the best conversion sequence.
In the case where the parameters of two compared overload are reference binding, the standard defines what is the best binding according to [over.ics.rank]/3.2.3 to [over.ics.rank]/3.2.6. These rule enable the compiler to choose whether foo(int&) or foo(int&&) is a better match for a given argument type.
But there are no rule that specifies if an argument passed by value is better than an argument bound to a reference parameter. So for this simple case where all overloads takes an int either by reference or by value, calling foo will always be ambiguous if the argument is not const. (If the argument type is const qualified, foo(int&) and foo(int&&) are not viable overloads).

How does std::variant becomes valueless_by_exception in this example?

this is example inspired by example from cppreference
struct S {
operator int() { throw 42; }
};
int main(){
variant<float, int> v{12.f}; // OK
cout << std::boolalpha << v.valueless_by_exception() << "\n";
try{
v.emplace<1>(S()); // v may be valueless
}
catch(...){
}
cout << std::boolalpha << v.valueless_by_exception() << "\n";
}
For one compiler I tried it outputs
false, true
meaning that emplace caused the variant to become valueless
What I do not understand is how this happened.
In particular I do not understand why emplace is called at all, I would expect the program to not even call it since conversion from S to int argument throws.
Note the signature for the relevant std::variant::emplace overload:
template <size_t I, class... Args>
std::variant_alternative_t<I, variant>& emplace(Args&&... args);
It takes a pack of forwarding references. This means that the conversion operator from S to int is not called when evaluating the function arguments; it's called inside the body of emplace. Since trying to construct the int in place would then fail, the variant is made valueless by exception.
It could perhaps be possible to implement variant such that for trivially movable types, the old value is saved before in place construction is attempted, and then restored if it failed, but I'm not sure if it fits in with the various restrictions on the type's implementation given by the standard.

Function overload using lambda function signature

Consider the following example
void foo(const std::function<int()>& f) {
std::cout << f() << std::endl;
}
void foo(const std::function<int(int x)>& f) {
std::cout << f(5) << std::endl;
}
int main() {
foo([](){return 3;});
foo([](int x){return x;});
}
This does not compile, because the call to foo is said to be ambiguous. As far as I understand this is due to the fact, that the lambda function is not a priori a std::function but has to be casted to it and that there is a std::function constructor that takes an arbitrary argument.
Maybe someone can explain to me why anyone would create an implicit constructor that takes an arbitrary argument. However my acutual question is whether there is a workaround, which allows to use the function signature of lambda functions to overload a the function foo. I have tried function pointers, but that didn't work because capturing lambda functions can't be cast to a normal function pointer.
Any help is most welcome.
Your compiler is correct according to C++11. In C++14, a rule is added that says that the constructor template shall not participate in overload resolution unless the type of the argument is actually callable with the std::function's argument types. Therefore, this code is supposed to compile in C++14, but not in C++11. Consider this to be an oversight in C++11.
For now, you can work around this by explicit conversion:
foo(std::function<int()>([](){return 3;}));
http://coliru.stacked-crooked.com/a/26bd4c7e9b88bbd0
An alternative to using std::function is to use templates. Templates avoid the memory allocation overhead associated with std::function. The template type deduction machinery will deduce the correct type of the lambda passed so the call site cast goes away. However you still have is disambiguate the overloads for the no-args vs args case.
You can do this using a trick with trailing return types that behave similar to enable_if.
template<typename Callable>
auto baz(Callable c)
-> decltype(c(5), void())
{
std::cout << c(5) << std::endl;
}
The above overload of baz will only be a valid overload candidate when the template parameter Callable can be called with an argument of 5.
You can put more advanced mechanisms on top of this to make it more general (ie. variadic pack expansion of args into callable) but I wanted to show the basic mechanism working.