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.
Related
If I call the "func(const generic& ref)" with an integer as argument (instead of a 'generic' object), the constructor generic(int _a) will be called to create a new object.
class generic {
public:
int a;
generic() {}
generic(int _a) : a(_a) {
std::cout << "int constructor was called!";
}
generic(const generic& in) : a(in.a) {
std::cout << "copy constructor was called!";
}
};
void func(const generic& ref) {
std::cout << ref.a;
}
int main() {
generic g(2);
func(g); // this is good.
func(generic(4)); // this is good.
func(8); // this is good...... ?
return 0;
}
The last "func(8)" call creates a new object using the constructor generic(int _a). Is there a name for this kind of construction? Shouldn't the programmer explicitly construct an object before passing the argument? Like this:
func(generic(8));
Is there any benefit in passing the integer alone (other than saving time)?
This behavior is part of overload resolution process - specifically.
When you call func(), the compiler constructs a list of candidates. There's only one candidate, func(const generic& ref), so the compiler tries to figure out how to make a call.
It sees that there is no func(int) defined, so it tries to find a conversion path from int to generic. Since there is a constructor of generic that takes an int, and there are no other conversions allowing to perform the same call, the compiler takes the construction+call path.
The compiler checks three things, in the order from higher to lower priority:
Exact match
Promotion
Conversion
This means that an exact match of the signature trumps a match that requires a promotion, and a match that requires a promotion trumps a match that needs a conversion.
See "Ranking of implicit conversion sequences" of the document linked above for information on how implicit conversions are applied.
Is there a name for this kind of construction? Shouldn't the programmer explicitly construct an object before passing the argument?
If you don't want this to happen, you can add the explicit specifier to your constructor:
explicit generic(int _a) : a(_a)
{
std::cout << "int constructor was called!";
}
An excerpt from the cppreference page:
A constructor that is declared without the function specifier explicit is called a converting constructor.
By default, implicit constructor calls are allowed in this circumstance.
Is there any benefit in passing the integer alone (other than saving time)?
Whether you call the method with func(8) or func(generic(8)) isn't going to change what code executes given the code you have written. If you were to add an overload of func that takes an int instead of a generic, then the calls would suddenly become different. So, although it is ultimately a matter of opinion, I think you are better off being explicit by using func(generic(8)).
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!
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.
I would like to prefer a certain implicit conversion sequence over another. I have the following (greatly simplified) class and functions:
class Whatever {...}
template <class T>
class ref
{
public:
operator T* ()
{
return object;
}
operator T& ()
{
return *object;
}
T* object;
...
};
void f (Whatever*)
{
cout << "f (Whatever*)" << endl;
}
void f (Whatever&)
{
cout << "f (Whatever&") << endl;
}
int main (int argc, char* argv[])
{
ref<Whatever> whatever = ...;
f(whatever);
}
When I have a ref object and I am making an ambiguous call to f, I would like the compiler to choose the one involving T&. But in other unambiguous cases I wish the implicit conversion to remain the same.
So far I have tried introducing an intermediate class which ref is implicitly convertible to, and which has an implicit conversion operator to T*, so the conversion sequence would be longer. Unfortunately it did not recognize in unambiguous cases that it is indeed convertible to T*. Same thing happened when the intermediate class had a(n implicit) constructor. It's no wonder, this version was completely unrelated to ref.
I also tried making one of the implicit conversion operators template, same result.
There's no "ranking" among the two conversions; both are equally good and hence the overload is ambiguous. That's a core part of the language that you cannot change.
However, you can just specify which overload you want by making the conversion explicit:
f((Whatever&) whatever);
Simple: define void f(const ref<Whatever>&), it will trump the others which require a conversion.
Only one user-defined conversion function is applied when performing implicit conversions. If there is no defined conversion function, the compiler does not look for intermediate types into which an object can be converted.
C++ does not allow polymorphism for methods based on their return type. However, when overloading an implicit conversion member function this seems possible.
Does anyone know why? I thought operators are handled like methods internally.
Edit: Here's an example:
struct func {
operator string() { return "1";}
operator int() { return 2; }
};
int main( ) {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
}
Conversion operators are not really considered different overloads and they are not called based on their return type. The compiler will only use them when it has to (when the type is incompatible and should be converted) or when explicitly asked to use one of them with a cast operator.
Semantically, what your code is doing is to declare several different type conversion operators and not overloads of a single operator.
That's not return type. That's type conversion.
Consider: func() creates an object of type func. There is no ambiguity as to what method (constructor) will be invoked.
The only question which remains is if it is possible to cast it to the desired types. You provided the compiler with appropriate conversion, so it is happy.
There isn't really a technical reason to prevent overloading of functions on the result types. This is done in some languages like Ada for instance, but in the context of C++ which has also implicit conversions (and two kind of them), the utility is reduced, and the interactions of both features would quickly leads to ambiguities.
Note that you can use the fact that implicit conversions are user definable to simulate overloading on result type:
class CallFProxy;
CallFProxy f(int);
class CallFProxy {
int myParameter;
CallFProxy(int i) : myParameter(i) {}
public:
operator double() { std::cout << "Calling f(int)->double\n"; return myParameter; }
operator string() { std::cout << "Calling f(int)->string\n"; return "dummy"; }
};
Overload resolution chooses between multiple candidate functions. In this process, the return type of candidates is indeed not considered. However, in the case of conversion operators the "return type" is critically important in determining whether that operator is a candidate at all.