Does declaring something like the following
void foo(int x) { std::cout << "foo(int)" << std::endl; }
void foo(const int &x) { std::cout << "foo(const int &)" << std::endl; }
ever make sense? How would the caller be able to differentiate between them? I've tried
foo(9); // Compiler complains ambiguous call.
int x = 9;
foo(x); // Also ambiguous.
const int &y = x;
foo(y); // Also ambiguous.
The intent seems to be to differenciate between invocations with temporaries (i.e. 9) and 'regular' argument passing. The first case may allow the function implementation to employ optimizations since it is clear that the arguments will be disposed afterwards (which is absolutely senseless for integer literals, but may make sense for user-defined objects).
However, the current C++ language standard does not offer a way to overload specifically for the 'l/r-valueness' of arguments - any l-value being passed as argument to a function can be implicitly converted to a reference, so the ambiguity is unavoidable.
C++11 introduces a new tool for a similar purpose — using r-value references, you can overload as follows
void foo(int x) { ... }
void foo(const int &&x) { ... }
... and foo(4) (a temporary, r-value passed as argument) would cause the compiler to pick the second overload while int i = 2; foo(i) would pick the first.
(note: even with the new toolchain, it is not possible to differentiate between the cases 2 and 3 in your sample!)
You could do this with a template:
template<typename T> void foo(T x) { ... }
Then you can call this template by value or by reference:
int x = 123;
foo<int>(x); // by value
foo<int const&>(x); // by refernce
How would the caller be able to differentiate between them?
It cannot be differentiated in this case. Both the overloaded functions have the same type of primitive data type as the argument. And taking by reference doesn't count for a different type.
You can use static_cast to explicitly select the overload to be called:
#include <iostream>
void foo(int x) { std::cout << "foo(int)" << std::endl; }
void foo(const int &x) { std::cout << "foo(const int &)" << std::endl; }
int main()
{
int x = 0;
auto f1 = static_cast< void(*)(int) >(foo);
f1(x);
auto f2 = static_cast< void(*)(const int&) >(foo);
f2(x);
}
However, you should ask yourself why you provided those two overloads in the first place. Either you are fine with making a copy or you are not. Both at the same time? Why? Also making it necessary for the caller to explicitly select the overload defeats the purpse of function overloading. If you really want that consider to supply two functions instead:
void foo_copying(int x) { std::cout << "foo(int)" << std::endl; }
void foo_non_copying(const int &x) { std::cout << "foo(const int &)" << std::endl; }
Not in C++. Functional languages such as Erlang and Haskell get closer by allowing you to specify function overloads based on parameter value, but most imperative languages including C++ require overloading based on method signature; that is, the number and type of each parameter and the type of the return value.
The const keyword in the signature defines not the type of the parameter, but its mutability within the function; a "const" parameter will generate a compiler error if modified by the function or passed by reference to any function that doesn't also use const.
The compiler can't.
Both definitions of foo can be used for all 'variants' of int.
In the first foo, a copy of the int is made. Copying an int is always possible.
In the second foo, a reference to a const int is passed. Since any int can be cast to a const int, a reference to it can be passed as well.
Since both variants are valid in all cases, the compiler can't choose.
Things become different if you e.g. use the following definition:
void foo (int &x);
Now calling it with foo(9) will take the first alternative, since you can't pass 9 as a non-const int reference.
Another example, if you replace int by a class where the copy constructor is private, then the caller can't make a copy of the value, and the first foo-variant will not be used.
Related
Does declaring something like the following
void foo(int x) { std::cout << "foo(int)" << std::endl; }
void foo(const int &x) { std::cout << "foo(const int &)" << std::endl; }
ever make sense? How would the caller be able to differentiate between them? I've tried
foo(9); // Compiler complains ambiguous call.
int x = 9;
foo(x); // Also ambiguous.
const int &y = x;
foo(y); // Also ambiguous.
The intent seems to be to differenciate between invocations with temporaries (i.e. 9) and 'regular' argument passing. The first case may allow the function implementation to employ optimizations since it is clear that the arguments will be disposed afterwards (which is absolutely senseless for integer literals, but may make sense for user-defined objects).
However, the current C++ language standard does not offer a way to overload specifically for the 'l/r-valueness' of arguments - any l-value being passed as argument to a function can be implicitly converted to a reference, so the ambiguity is unavoidable.
C++11 introduces a new tool for a similar purpose — using r-value references, you can overload as follows
void foo(int x) { ... }
void foo(const int &&x) { ... }
... and foo(4) (a temporary, r-value passed as argument) would cause the compiler to pick the second overload while int i = 2; foo(i) would pick the first.
(note: even with the new toolchain, it is not possible to differentiate between the cases 2 and 3 in your sample!)
You could do this with a template:
template<typename T> void foo(T x) { ... }
Then you can call this template by value or by reference:
int x = 123;
foo<int>(x); // by value
foo<int const&>(x); // by refernce
How would the caller be able to differentiate between them?
It cannot be differentiated in this case. Both the overloaded functions have the same type of primitive data type as the argument. And taking by reference doesn't count for a different type.
You can use static_cast to explicitly select the overload to be called:
#include <iostream>
void foo(int x) { std::cout << "foo(int)" << std::endl; }
void foo(const int &x) { std::cout << "foo(const int &)" << std::endl; }
int main()
{
int x = 0;
auto f1 = static_cast< void(*)(int) >(foo);
f1(x);
auto f2 = static_cast< void(*)(const int&) >(foo);
f2(x);
}
However, you should ask yourself why you provided those two overloads in the first place. Either you are fine with making a copy or you are not. Both at the same time? Why? Also making it necessary for the caller to explicitly select the overload defeats the purpse of function overloading. If you really want that consider to supply two functions instead:
void foo_copying(int x) { std::cout << "foo(int)" << std::endl; }
void foo_non_copying(const int &x) { std::cout << "foo(const int &)" << std::endl; }
Not in C++. Functional languages such as Erlang and Haskell get closer by allowing you to specify function overloads based on parameter value, but most imperative languages including C++ require overloading based on method signature; that is, the number and type of each parameter and the type of the return value.
The const keyword in the signature defines not the type of the parameter, but its mutability within the function; a "const" parameter will generate a compiler error if modified by the function or passed by reference to any function that doesn't also use const.
The compiler can't.
Both definitions of foo can be used for all 'variants' of int.
In the first foo, a copy of the int is made. Copying an int is always possible.
In the second foo, a reference to a const int is passed. Since any int can be cast to a const int, a reference to it can be passed as well.
Since both variants are valid in all cases, the compiler can't choose.
Things become different if you e.g. use the following definition:
void foo (int &x);
Now calling it with foo(9) will take the first alternative, since you can't pass 9 as a non-const int reference.
Another example, if you replace int by a class where the copy constructor is private, then the caller can't make a copy of the value, and the first foo-variant will not be used.
Consider the following piece of code:
#include <iostream>
using namespace std;
class A {
private:
int x;
public:
int& get_ref() {
cerr << "non const" << endl;
return x;
}
const int& get_ref() const {
cerr << "const" << endl;
return x;
}
};
int main () {
A a;
a.get_ref() = 10;
cout << a.get_ref() << endl;
const int& y = a.get_ref();
return 0;
}
I expect the second and third calls to a.get_ref() to run the second version of get_ref() method (and output const on the standard error). But it looks like always the first version is called. How can I implement two different 'getter's and make sure that the proper version is called based on the context? I.e., at least for the third call
const int& y = a.get_ref();
the second version is executed? (A non-elegant solution would be to use different names e.g. get_ref and get_const_ref but I am trying to see if that can be avoided.)
Overload resolution doesn't depend on return values, but only arguments, including the object to be called on for member function. a is a non-const object, then for a.get_ref(), the non-const member function will always be called.
You can cast it to const for the const version to be called:
const_cast<const A&>(a).get_ref();
BTW: Giving them different names is not a bad idea. That's why we have std::cbegin and std::cend in STL.
Overload resolution is concerned only with the arguments of the call (including the implicit argument for this). The expression a.get_ref() must evaluate to the same overload regardless of what happens with its returned value. That is fundamental in C++, and there's nothing you can do about it.
If you want to call the const-qualified version, use a const-qualified object expression:
const int& y = const_cast<const A&>(a).get_ref();
After digging to find the source of a bug, I was surprised to discover that the following seems to be legal C++11 (compiles fine with GCC/clang with Wall). In particular, why can I assign f1, which takes its argument by value to a RefFunction which expects an argument by reference ?
I tried googling for an explanation, but didn't find anything relevant, probably because I don't know exactly what to google for. I'd really appreciate if someone can guide me through why this is legal.
#include <iostream>
using namespace std;
void f1(int val) {
val = 1;
}
void f2(int& val) {
val = 2;
}
using RefFunction = std::function<void(int&)>;
int main()
{
using namespace std::placeholders;
int val = 42;
// I was expecting a compile error here telling me that f1 doesn't
// have the right signature (int instead of int&)
RefFunction f = f1;
f(val);
cout << val << endl; // prints 42
// This makes sense, f2 takes argument by reference
f = f2;
f(val);
cout << val << endl; // prints 2
return EXIT_SUCCESS;
}
Setting aside the standardese for the time being, think in terms of the following:
void f1(int val) {
val = 1;
}
void f2(int& val) {
val = 2;
}
void WrapperFunction(int& val)
{
f1(val); // Should be OK
f2(val); // Should be OK.
}
The compiler should not have any problems with the above code. If you think of WrapperFunction analogous to a std::function, the compiler should not have any problem regardless of whether the std::function is constructed with f1 or f2.
The template argument of std::function enforces the manner in which the std::function may be called; therefore a RefFunction can only be called with an lvalue of type int or something that can be implicitly converted to an lvalue of type int. It will then call the underlying function, f1 or f2. A function that receives a reference to int can always use that reference to call a function that takes int by value; the int referred to will simply be copied.
In general std::function<R(T...)> can store a callable with any signature as long as it's true that the T... parameters of the std::function's function call operator can actually be used to call the underlying callable. The signatures don't need to match exactly.
I am trying to understand the rules of c++ automatic and explicit conversions in regular or member function calls. I wrote the following code and it fails compilation:
#include <iostream>
#include <string>
using namespace std;
class testExplicit {
public:
int intval;
short shortval;
double doubleval;
char charval;
string strval;
testExplicit(int a1, short a2, double a3, char a4, string& a5):
intval(a1),shortval(a2),doubleval(a3),charval(a4),strval(a5){}
void getVal(int& a) { a = intval; cout << "IntVal\n"; }
// void getVal(short& a) { a = shortval; cout << "Short Val\n"; }
// void getVal(double& a) { a = doubleval; cout << "Double Val\n"; }
// void getVal(char& a) { a = charval; cout << "Char Val\n"; }
// void getVal(string& a) { a = strval; cout << "String Val\n"; }
};
int main( int argc, char **argv ) {
string s ("test Str");
testExplicit test (100,10,10.05,5,s);
int i;
char c;
double d;
short f;
test.getVal(i);
test.getVal(c);
test.getVal(d);
test.getVal(f);
return 0;
}
However, can I conclude that the functions only expect the exact matching parameter? I remember reading that automatic conversions happen according to the conversion rules. Can some shed some light on the correct rules pls?
Here is the error:
test.cpp: In function 'int main(int, char**)':
test.cpp:38: error: no matching function for call to 'testExplicit::getVal(char&)'
test.cpp:17: note: candidates are: void testExplicit::getVal(int&)
test.cpp:39: error: no matching function for call to 'testExplicit::getVal(double&)'
test.cpp:17: note: candidates are: void testExplicit::getVal(int&)
test.cpp:40: error: no matching function for call to 'testExplicit::getVal(short int&)'
test.cpp:17: note: candidates are: void testExplicit::getVal(int&)
Thanks
void getVal(int& a);
This function takes an int by reference. You must pass it an int. This is similar to how if you had a function
void getVal(int* a);
you would need to pass it a pointer to an int (not a pointer to a short or any other type).
One reason for this is that you are able to modify the int from within the function. In order to allow you to pass an object of another type (e.g. a short) to this function, a temporary object of type short would have to be created at runtime and a reference to that temporary object would have to be passed.
This wouldn't be ideal because you might accidentally end up passing the wrong type of object (e.g. a short) and expecting it to be modified by the function, when in fact a temporary copy of type int would be modified by the function, not the original short.
You are, however, permitted to bind const references to temporary objects, so if your function was declared as
void getVal(const int& a);
you would be able to pass it any type that is convertible to int. This makes some sense, since the function cannot modify the referenced object (because it is a const reference), so the "oops, I'm accidentally modifying a temporary object" problem doesn't exist.
Conversions can also take place when you pass by value, but this too makes sense: when you pass by value, a copy has to be made anyway (the copy that is passed to the function by value), so the conversion can take place as part of that copy.
The problem is that if an implicit conversion is required, then a temporary variable is created. You cannot have a non-const reference to a temporary variable, so you would need to make your member function void getVal(const int &a) or void getVal(int a).
Implicit conversion should be avoided. C++ is a strongly typed language it is far better to create functions for the types you wish to accept, use templates, or explicitly cast your type to another type, etc.
Constructor casting or using static_cast<>, dynamic_cast<>, or reinterpret_cast<> are some of the options depending on the situation when you need to convert types from one to another.
Templates can allow you to handle multiple types a little easier.
template<typename T>
void getVal(const T& a)
{
// do something
}
Implicit conversions are done by creating an rvalue (temporary), and rvalues cannot be bound to non-const references. That is the reason why it is not working. If, on the other hand you change the signature to take the arguments either by value or by constant reference, then it will work:
void f( int a ) { std::cout << a << std::endl; }
void g( const int& b ) { std::cout << b << std::endl; }
int main() {
char c = 'a'; // note that this the ASCII value of 'a'
f( c );
g( c );
short s = 4;
f( s );
g( s );
}
Pass by reference means, creating an alias for the same type. So try changing void getVal(int& a) to void getVal(int a), to work for the other function calls differing the passing parameter type
I have written the following code:
#include "stdafx.h"
#include <iostream>
using namespace std;
double funcA()
{
return 100.0;
}
int g(double (*pf)())
{
cout << (*pf)() << endl;
return 0;
}
int g2(double pf())
{
cout << pf() << endl;
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
g(&funcA); // case I
g(funcA); // case II
g2(funcA); // case III
g2(&funcA); // case IV
return 0;
}
I have run the above code on VS2008 and each function call returns '100'.
Here is the question:
Q1> Is there any problem in the code?
Q2> It seems that C++ doesn't make difference between *pf and pf. Is that correct?
Thank you
C++ does, in fact, make a distinction between the types double() and double(*)(), but the difference is subtle. When you pass a function type as an argument to a function, the function-type automatically "degrades" to a function pointer. (This is similar, I suppose, to how an array type degrades to a pointer type when passed as a function argument.)
However, a function type and a function-pointer type are still different types, according to the C++ type-system. Consider the following case:
void g() { }
template <class F>
struct Foo
{
Foo(const F& f) : func(f)
{ }
void operator()() { func(); }
F func;
};
int main ()
{
Foo<void()> f(g);
f();
}
This should fail to compile, since you cannot declare a function type as an automatic variable. (Remember, functions are not first-class objects in C++.) So the declaration F func; is invalid. However, if we change our main function to instead instantiate the template using a function pointer, like so:
int main ()
{
typedef void(*function_pointer)();
Foo<function_pointer> f(g);
f();
}
...now it compiles.
The following functions are identical:
int g(double (*pf)())
{
cout << (*pf)() << endl;
return 0;
}
int g2(double pf())
{
cout << pf() << endl;
return 0;
}
Dereferencing a function pointer (as shown in g) is the same as calling that function's name.
Q2> It seems that C++ doesn't make
difference between *pf and pf. Is that
correct?
There is a difference between *pf and pf (as variables). If pf is a function, *pf and pf() are identical (Note the parentheses).
With most modern compilers, there is no difference between "(*variable)." and "variable->". However, one must check the class in use to see if it overrides the dereference operator.
Many programmers use typedef when defining function pointers, primarily to make reading easier. Also, the double pf() syntax may be prone to readability errors and can get confused with executing a function on parameter line.
There's no problem or difference in the code you posted. However, if you are writing templates which take functors, you should use the syntax in g2. Consider the following:
template<typename Iter, typename Func>
void for_each(Iter begin, Iter end, Func functor)
{
for(; begin != end; ++begin)
{
functor(*begin);
}
}
Note that if you put the dereference operator before functor, you limit the utility of the algorithm you have written to function pointers. However, if you don't put that there, someone can pass an STL functor, such as something returned by std::bind2nd.
Therefore I would overall recommend using the second (without *) syntax where possible.
Consider the following piece of code
void pf();
void (&prf)() = pf; // OK, bind prf to pf
void (&prf)() = &pf; // ill-formed, can't bind prf to an function pointer value
On the other hand
void (*ppf)() = pf; // OK, function decays to a pointer
void (*ppf)() = &pf; // OK, pointer assigned to a pointer
So there is an implicit conversion from a function to a pointer (which is called "decay"). This also makes you able to say ***...***pf - arbitrarily many times dereference it - in each step a function to pointer conversion occurs which undoes the effect of the previous dereference.
In function parameter lists, a T f() and a T (*f)() are equivalent ways (except for spelling) of declaring a parameter
void f(void g()); // g has type void (*)()
void f(void (*g)()); // g has type void (*)()
A reference will inhibit this parameter type adjustment
void f(void (&g)()); // g has *not* the type void (*)()
This is exactly the same as for array declared parameters: Parameters are never arrays, but they will always be pointers, if they were declared as being arrays.