I am curious why there is a difference in the argument evaluation order between chained static functions and member functions. From the answers at this question I can see it is unspecified what the argument evaluation order is between such chained function calls. Take for example the following snippet:
#include <iostream>
class test {
public:
static test& chain_s(test& t, int i) {
std::cout << i << " ";
return t;
}
test& chain(test& t, int i) {
std::cout << i << " ";
return *this;
}
};
int main(int, char**) {
int x = 2;
test t;
t.chain(t,++x).chain(t,++x).chain(t,++x);
x = 2; std::cout << std::endl;
t.chain_s(t,++x).chain_s(t,++x).chain_s(t,++x);
return 0;
}
In the case of GCC 4.6.2 and CL 15.00.30729.01 (MSVC 9) the resulting output is for me
5 5 5
3 4 5
However, I was wondering if there is any reason in the specification or if it is otherwise known why the static function are evaluated left-to-right (with their arguments), and for the non-static function all the arguments first (right-to-left from what I've seen in other tests).
The reason I'm asking this is because I first noticed this difference in behavior when trying to get similar behavior in C (using a struct and a function pointer) and failed. I strongly suspect this is some optimization implemented both in GCC and MSVC for member functions, but I hope someone here can shed a little more light on this.
Edit:
I forgot to mention one crucial bit of information which strikes me as odd: GCC will only warn on unspecified behavior on the chained non-static function, but not the static functions:
a.cpp: In function 'int main(int, char**)':
a.cpp:18:45: warning: operation on 'x' may be undefined [-Wsequence-point]
GCC is not obligated to provide such warnings so it could miss the second expression, but this is what leads me to believe something interesting is going on.
No reason. Like you say, the order is unspecified by the language.
One reason for using right to left order is that functions with a variable number of parameters, like printf, will then always have the first parameter on top. Otherwise it doesn't matter.
Your code has undefined behavior, but I suppose you know that. Also,
you could easily see a difference depending on optimization flags. But
in this case, one likely reason is that the non-static functions require
three arguments, including the results of the previous call, where as
the static functions only require two, and the results of the previous
call are ignored.
Related
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.
I am curious why there is a difference in the argument evaluation order between chained static functions and member functions. From the answers at this question I can see it is unspecified what the argument evaluation order is between such chained function calls. Take for example the following snippet:
#include <iostream>
class test {
public:
static test& chain_s(test& t, int i) {
std::cout << i << " ";
return t;
}
test& chain(test& t, int i) {
std::cout << i << " ";
return *this;
}
};
int main(int, char**) {
int x = 2;
test t;
t.chain(t,++x).chain(t,++x).chain(t,++x);
x = 2; std::cout << std::endl;
t.chain_s(t,++x).chain_s(t,++x).chain_s(t,++x);
return 0;
}
In the case of GCC 4.6.2 and CL 15.00.30729.01 (MSVC 9) the resulting output is for me
5 5 5
3 4 5
However, I was wondering if there is any reason in the specification or if it is otherwise known why the static function are evaluated left-to-right (with their arguments), and for the non-static function all the arguments first (right-to-left from what I've seen in other tests).
The reason I'm asking this is because I first noticed this difference in behavior when trying to get similar behavior in C (using a struct and a function pointer) and failed. I strongly suspect this is some optimization implemented both in GCC and MSVC for member functions, but I hope someone here can shed a little more light on this.
Edit:
I forgot to mention one crucial bit of information which strikes me as odd: GCC will only warn on unspecified behavior on the chained non-static function, but not the static functions:
a.cpp: In function 'int main(int, char**)':
a.cpp:18:45: warning: operation on 'x' may be undefined [-Wsequence-point]
GCC is not obligated to provide such warnings so it could miss the second expression, but this is what leads me to believe something interesting is going on.
No reason. Like you say, the order is unspecified by the language.
One reason for using right to left order is that functions with a variable number of parameters, like printf, will then always have the first parameter on top. Otherwise it doesn't matter.
Your code has undefined behavior, but I suppose you know that. Also,
you could easily see a difference depending on optimization flags. But
in this case, one likely reason is that the non-static functions require
three arguments, including the results of the previous call, where as
the static functions only require two, and the results of the previous
call are ignored.
#include <iostream>
using namespace std;
void somefunc(int a)
{
cout<<"somefunc1";
}
void somefunc(int &b)
{
cout<<"somefunc2";
}
int main()
{
// case 1
somefunc(10); // works fine and prints somefunc1
//case2
int b=10;
somefunc(b); // generates compiler error that overloading is ambiguous
return 0;
}
In main() if I pass a constant (say 10) program compiles and runs and prints "somefunc1", but when I pass a variable (b in this case) compiler generates an error that overloading is ambiguous.
I don't understand how is it working internally.
Please help!!
The rules for overload resolution are a bit complicated. This is a simplification, applicable to this particular example.
The first step the compiler goes through is finding the "overload set", that is, the set of functions that can be called with the argument. For somefunc(10), only somefunc(int) can be called; somefunc(int&) cannot be called, because 10, being a constant, can't be passed by (non-const) reference. So there's only one function in the overload set, and that's the one that gets called.
For somefunc(b), both functions can be called. So the overload set has two functions, somefunc(int) and somefunc(int&). Now the compiler has to determine which function is the "best match" for the argument 10. And the rule is that int and int& both provide an "exact match", so the rules do not prefer one over the other, and the call is ambiguous.
If the second version of the function had been somefunc(const int&) instead of somefunc(int&) the call somefunc(10) would also be ambiguous.
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.
I'm confused by this situation and googling didn't give me the answer. Basically I have the following simple code that doesn't compile:
#include <iostream>
class A
{
public:
int a(int c = 0) { return 1; }
static int a() { return 2; }
};
int main()
{
std::cout << A::a() << std::endl;
return 0;
}
In compiling this, GCC 4.2 says the call to A::a() in main() is ambiguous with both versions of a() valid candidates. Apple's LLVM compiler 3.0 compiles with no error.
Why is gcc confused about which function I want to call? I thought it was obvious that by qualifying a() with A:: I'm asking for the static version of the function. Naturally this code still doesn't compile if I remove the static function a(), because A::a() is not valid syntax for calling the non-static a().
Thanks for any comment!
The reason for this is because C++ specifies that this is ambiguous. Overload resolution specifies that for A::a, since this is not in scope, the argument list in that call is augmented by a contrived A object argument, instead of *this. Overload resolution does not exclude non-static member functions, but instead
If the argument list is augmented by a contrived object and overload resolution selects one of the non-static member functions of T, the call is ill-formed.
This has recently been subject of extensive discussion both in the committee in context of core issue 1005. See core issue 364 which considered changing this rule but didn't do so.
The reason is name resolution happens before anything else the compiler does, like figuring out which overloaded function to use.
Qualifying the function with A:: simply tells the compiler to "look inside of A to find the name a". It doesn't actually help resolve which function you are referring to.
EDIT
And so when you type A::a(), first the compiler thinks "look in A for a member function or member who can use operator()".
Then the compiler thinks, "Ok, two possibilities here, which one is being referred to? a() or a(int c = 0) with a default c=0. Not sure.
If you removed the static keyword and called the functions like obj.a(), there would still be an ambiguity.
WRT LLVM's parser
I would say that it does some extra work for you, which is not required by the standard, which would be to assume A::a() is static.