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.
Related
Consider following code:
#include <iostream>
void foo(int m);
void foo(int &k);
int main()
{
foo(5); // ok, because there is no ambiguity
int m = 5;
//foo(m); // compile-time error, because of ambiguity
foo(m + 0); // ok, because it's an expression of type int and not object's lvalue
}
void foo(int m)
{
std::cout << "by value\n";
}
void foo(int &k)
{
std::cout << "by reference\n";
}
I understand that it introduces ambiguity for foo(m), but is this allowed, when expression is of type int (or another that can be converted to int)?
I have tried to find some standard reference on this, yet with no luck.
Disclaimer: Note that it's not duplicate of Function Overloading Based on Value vs. Const Reference. The const references are different as they can be assigned with rvalues, as opposite to "ordinary", non-const references.
13.1 [over.load] is pretty clear (apart from a multi-page note) about which functions cannot be overloaded in the same scope.
Your case is not listed there, and you can declare those overloads, you just can't necessarily use them easily. You could call the lvalue one like so:
void (*f)(int&) = foo;
f(m);
This avoids the ambiguity that happens when you call foo(m).
Aside: another way to write foo(m + 0) is simply foo(+m), the unary + operator converts the lvalue to an rvalue, so the foo(int) overload is called.
Yes, it is allowed.
There is no rule to prevent this overload.
[C++14: 13.1/1]: Not all function declarations can be overloaded. Those that cannot be overloaded are specified here. [..]
[C++14: 13.1/2]: (blah blah lots of exceptions not including any for this case)
It would be extremely limiting for the language to prohibit function overloads that may be ambiguous in certain scenarios with certain calls, and for no good reason I might add!
I'm trying to see default argument promotion in functions. Specifically I want to test section 6.5.2.2 Function calls (described here).
I want to have a prototype-less function call to see default argument promotion to integer but I get "Function does not take 1 arguments" error. This is what I'm trying to do:
#include<iostream>
using namespace std;
//void Func(char val);
//void Func(int val);
void Func(); // No prototype
int main(int argc, char** argv)
{
char charVal = 'a';
cout << "Func(charVal) - "; Func(charVal);
return 0;
}
void Func(char val)
{
cout << "Char arg. Result: " << val << endl;
}
void Func(int val)
{
cout << "Int arg. Result: " << val << endl;
}
I expected to see Func(int) being called due to argument promotion.
Is this removed from the standard already?
Cheers.
P.S- I just saw that this kind of prototype-less declarations are part of C standard, NOT C++. Any particular reason why C++ doesn't support it?
All functions (and named entities in general) need to be declared before use. You've only declared the overload with no parameters (which is what an empty parameter list means in C++) when you try to call it with an argument in main.
You have the correct declarations at the start of the file, but for some reason the one you need is commented out. Uncomment them and it's fine.
I just saw that this kind of prototype-less declarations are part of C standard, NOT C++. Any particular reason why C++ doesn't support it?
Because C++ supports overloading. Overload resolution happens at compile time, where the function is called, and candidates can only be considered if the compiler knows they exist - that is, if they've been fully declared so that the compiler can match their signatures against the argument types of the function call.
In C, the compiler knows which function you mean, whether or not it knows the parameter types, since it's the only one with that name. Such declarations are merely dangerous, removing type-checking from the argument types and opening the door to all manner of bugs.
C++ has never supported prototype-less function declarations. The empty argument list in C++ means no arguments, not a lack of prototype.
The reason is that C++ has type-safe linking, and that just doesn't work if you don't have a prototype. And C++ has type-safe linking because that's just a good idea and reduces bugs. (You can read Design&Evolution of C++ for more details.)
Argument promotions in C++ exist only in calls to true variadic functions, i.e. those declared with a ... in the argument list.
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.
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.
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.