When the function is called it's clear how name-lookup and overload resolution is performed. But what happens when the funtion is not being called? E.g.
#include <iostream>
using std::cout;
using std::endl;
void foo(int){ cout << "foo(int)" << endl; }
void foo(int, int){ cout << "foo(int, int)" << endl; }
void (*baz)(int, int);
int main()
{
baz = foo; //1
baz(1, 1);
}
DEMO
In that case we have two functions with the name foo and formally, the unqualified name lookup finds both them. The clause 13 of the Standard doesn't cover that case because it's concerned only in the function call context N3797:13.3/2 [over.match]:
Overload resolution selects the function to call in seven distinct
contexts within the language:
The behavior in this case is governed by this verbiage in the C++11 standard (there is a similar section in N3797):
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. ... The function selected
is the one whose type is identical to the function type of the target type required in the context. -- ISO/IEC 14882:2011(E) §13.4 [over.over] (emphasis mine)
The standard overload resolution rules aren't used here because you are assigning to a function pointer type, so the compiler will simply select the function overload that exactly matches the type of the function pointer.
Related
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.
The following code snippet:
#include <iostream>
void does() { std::cout << "do" << std::endl; }
void does(bool b = false) { std::cout << "do(bool)" << std::endl; }
void fwd(void (*func)(bool))
{
func(false);
}
int main(int, char**)
{
fwd(&does);
fwd(does);
fwd(*does);
}
understandably produces the following error:
test.cpp:15:10: error: overloaded function with no contextual type information
The compiler cannot discern which of the functions I intend to use.
What I don't understand is why the code will correctly run when I comment out the line that reads:
fwd(*does)
Why can the compiler suddenly resolve the ambiguousness?
int main(int, char**)
{
fwd(&does);
fwd(does);
}
Also, without overloading does the snippet will correctly run with all 3 calls.
This snippet runs fine...
#include <iostream>
void does(bool b = false) { std::cout << "do(bool)" << std::endl; }
void fwd(void (*func)(bool))
{
func(false);
}
int main(int, char**)
{
fwd(&does);
fwd(does);
fwd(*does);
}
I'm compiling this with gcc 4.6.3 on a Linux box.
Thanks for the help!
The answer to your question is in the overload-resolution rules for functions.
Specifically, there is an exception for using & before the function-name (once) not breaking overload-resolution, but none for using *.
Also see that only one of those two functions accept that single argument:
13.4 Address of overloaded function [over.over]
1 A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context. [ Note: That is, the class of which the function is a member is ignored when matching a pointer-to-member-function type. —end note ] The target can be
an object or reference being initialized (8.5, 8.5.3),
the left side of an assignment (5.17),
a parameter of a function (5.2.2),
a parameter of a user-defined operator (13.5),
the return value of a function, operator function, or conversion (6.6.3),
an explicit type conversion (5.2.3, 5.2.9, 5.4), or
a non-type template-parameter (14.3.2).
The overloaded function name can be preceded by the & operator. An overloaded function name shall not be used without arguments in contexts other than those listed.
Quote is from n3242 (c++11), with bold by me.
fwd expects a function that takes a boolean parameter; you only have one such version of does, so there is no confusion. In effect, does and &does are considered the same (because functions cannot be values, one of these two should technically be incorrect if not impossible to represent, but the language has to chosen to instead just treat them as the same thing).
But when you try to use fwd(*does), you would need a definition of does that dereferences to such a function, and you don't have anything like that -- in fact, as I have been recently schooled, you can't have anything like that.
What do the characters in bold mean in this sentence extracted from paragraph §5.2.2/1 of the C++11 Standard?
There are two kinds of function call: ordinary function call and member function (9.3) call. A function call is a postfix expression followed by parentheses containing a possibly empty, comma-separated list of expressions which constitute the arguments to the function. For an ordinary function call, the postfix expression shall be either an lvalue that refers to a function (in which case the function-to-pointer standard conversion (4.3) is suppressed on the postfix expression), or it shall have pointer to function type.
Edit
Basically what I'm asking is: when the Standard says "(in which case the function-to-pointer standard conversion is suppressed on the postfix expression)" does it mean that this suppression is for good or that it will be revoked later (e.g. after function overloading)?
Edit1
In my opinion the word "suppressed" above is misleading since it gives the impression that the conversion from function name to a function pointer might never be done by the compiler. I believe that's not the case. This conversion will always occur after the function overloading process is finished, since only at this point, the compiler knows exactly which function to call. That's not the case when the program initializes a function pointer. In this situation, the compiler knows the function to be called, so there will be no overloading, as the example below shows.
#include <iostream>
int foo(int i) { std::cout << "int" << '\n'; return i * i; }
double foo(double d) { std::cout << "double" << '\n'; return d * d; }
int main()
{
int(*pf)(int) = foo; // no overloading here!
std::cout << pf(10.) << '\n'; // calls foo(int)
std::cout << foo(10.) << '\n'; // call foo(double) after function overloading. Therefore, only after function
// overloading is finished, the function name foo() is converted into a function-pointer.
}
The code prints:
int
100
double
100
Absent any statement in the Standard to the contrary, the suppression is presumably permanent. I think the conversion is suppressed because (i) overload resolution needs to take place and (ii) it is not necessary in this situation. Indeed, it would be impossible to convert to a pointer before we knew exactly which function is being called. After overload resolution, we know we are directly calling the function, so a conversion would be pointless.
Here is the source code similar to the surrogate call functions that I read on the post "Hidden features in C++"
The only part that confuses me is those operator overloaded functions.
What kind of operators are they? (They certainly don't seem like ordinary operator()'s, and why is it returning a function pointer even though there is no return type specified?
Thanks!
template <typename Fcn1, typename Fcn2>
class Surrogate {
public:
Surrogate(Fcn1 *f1, Fcn2 *f2) : f1_(f1), f2_(f2) {}
// Overloaded operators.
// But what does this do? What kind of operators are they?
operator Fcn1*() { return f1_; }
operator Fcn2*() { return f2_; }
private:
Fcn1 *f1_;
Fcn2 *f2_;
};
void foo (int i)
{
std::cout << "foo: " << i << std::endl;
}
void bar (double i)
{
std::cout << "bar: " << i << std::endl;
}
int main ()
{
Surrogate<void(int), void(double)> callable(foo, bar);
callable(10); // calls foo
callable(10.1); // calls bar
return 0;
}
They are implicit type conversion operators to Fcn1* and Fcn2*.
In the expression "callable(10)" callable is converted by the compiler to pointer to function with int parameter, using the first one of the type conversion operators defined in Surrogate. That function is then invoked.
The call callable(10); actually is *(callable.operator void(*)(int))(10);.
The compiler has figured out that callable is used in a function call expression. Now, for a function call expression the compiler would like a function, function pointer, or object with operator() - as you already know.
In this case, callable is none of these. But callable can be converted to one of these, namely to a function pointer. Given the call expression, in particular the int argument, overload resolution selects void(*)(int).
These are just user-defined conversion operators. User-defined conversion operators is a basic feature of C++ language, meaning that you can read about them in C++ book or in some tutorial.
Section 12.3.2 of language specification describes the syntax, but the rules that govern their usage by the compiler are scattered across the entire document and are relatively extensive. I.e. it is not something that can or should be explained in a SO post.
Find a book. Come back here if something in the book is not clear to you.
Why my VS2010 can't compile this code:
#include <functional>
#include <vector>
int main()
{
std::vector<int> vec;
std::bind(&std::vector<int>::push_back, std::ref(vec), 1)();
return 0;
}
You should be more specific why this doesn't seem to work for you.
#include <iostream>
#include <tr1/functional>
#include <vector>
int main(int argc, char* argv[]) {
std::vector<int> vec;
std::tr1::bind(&std::vector<int>::push_back, std::tr1::ref(vec), 1)();
std::cout << "vec.size = " << vec.size() << std::endl;
std::cout << "vec[0] = " << vec[0] << std::endl;
return 0;
}
$ gcc -o test -lstdc++ test.cpp && ./test
vec.size = 1
vec[0] = 1
Update: Luc Danton is right, the issue here is the overloaded push_back. See question Are there boost::bind issues with VS2010 ?. Also, note that the issue is not limited to push_back, see Visual Studio 2010 and boost::bind.
The bottom line is that what you're trying to do isn't possible in portable C++. std::vector<>::push_back is guaranteed to be overloaded in C++11 compilers, as at a minimum there must be an overload for lvalues and an overload for rvalues.
Usually, when taking the address of an overloaded member function, §13.4/1 in the C++11 FDIS tells us that we can control which overload we're taking the address of thusly:
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context. [ Note: That is, the class of which the function is a member is ignored when matching a pointer-to-member-function type. —end note ] The target can be
an object or reference being initialized,
the left side of an assignment,
a parameter of a function,
a parameter of a user-defined operator,
the return value of a function, operator function, or conversion,
an explicit type conversion, or
a non-type template-parameter.
The overloaded function name can be preceded by the & operator. An overloaded function name shall not be used without arguments in contexts other than those listed. [ Note: Any redundant set of parentheses surrounding the overloaded function name is ignored. —end note ]
The problem comes from §17.6.5.5/2:
An implementation may declare additional non-virtual member function signatures within a class by adding arguments with default values to a member function signature; hence, the address of a member function of a class in the C++ standard library has an unspecified type.
Consequently, it is not portable to ever take the address of a standard library class member function, as the type of such an expression is by definition unknowable except on an implementation-by-implementation basis.
Luc Danton's proposed workaround (specifically, using a lambda) is also what I would recommend:
std::vector<int> vec;
[&](){ vec.push_back(1); }();
Try this:
struct push_back {
void
operator()(std::vector<int>& vector, int i) const
{
vector.push_back(i);
}
};
// somewhere else:
std::vector<int> vec;
std::tr1::bind(push_back(), std::tr1::ref(vec), 1)();
With C++03 note that push_back cannot be a local type; with C++11 it can but it would be more idiomatic (and completely equivalent) to use a lambda.
In all likeliness your implementation provides overloads for std::vector<T>::push_back and thus its address would have to be disambiguated. If this is what happened, your compiler should have provided you with an appropriate error message. In all cases, you should explain what you mean by "it's not possible".
The point is not to use such helper
functions. – magenta
Then why didn't you put it in the question? I can't read your mind.
You can also try this:
std::vector<int> vec;
void (std::vector<int>::*push_back)(int const&) = &std::vector<int>::push_back;
std::tr1::bind(push_back(), std::tr1::ref(vec), 1)();
Which I believe is not guaranteed to success.
It should propably lok like this:
std::vector<int> vec;
std::tr1::bind(&std::vector<int>::push_back, std::tr1::ref(vec), _1)(1);