int transforms into int&? - c++

code snippet:
// some code
SDL_Surface* t = Display->render_text(text);
int z=100;
Display->blit_image(t,z,100);
// some more code
does not compile because z magically changes to an int&,
file.cpp:48: error: no matching function for call to ‘display::blit_image(SDL_Surface*&, int&, int)
how can this happen?
post scriptum:
the following works if i put them in place of Display->blit_image(t,z,100)
Display->blit_image(t,z,100,0);
but i am sure that th 4th param is optional because the exact same function works elsewhere without it
pps: i created a minimal-case of my code that behaves as describd above
it's 3 files:
monkeycard.cpp: http://pastebin.com/pqVg2yDi
display.hpp: http://pastebin.com/xPKgWWbW
display.cpp: http://pastebin.com/nEfFX1wj
g++ -c display.cpp monkeycard.cpp fails with:
monkeycard.cpp: In member function ‘void monkeycard::messagebox(std::string)’:
monkeycard.cpp:28: error: no matching function for call to ‘display::blit_image(SDL_Surface*&, int&, int)’
display.hpp:26: note: candidates are: void display::blit_image(SDL_Surface*, int, int, SDL_Rect*)

The error message tells you what you're trying to pass. With automatic conversions and whatnot, that doesn't mean the function must have exactly that signature.
int& here just means that the parameter you've provided is an lvalue, and so it could be passed as a non-const reference. A function can match with that parameter as an int&, const int&, int, long, const float&, etc.
the point is that if instead of z i
write 100 it works.
That's interesting. I can't immediately think of a way to write a function that accepts an integer literal, but not an integer variable. The following code compiles, of course:
struct SDL_Surface;
struct SDL_Rect;
struct display {
void foo(SDL_Surface* img, int x=0, int y=0, SDL_Rect* clip=0) {}
};
int main() {
display d;
int z = 0;
SDL_Surface *p = 0;
d.foo(p,z,100);
}
So there must be something else you haven't mentioned yet, which causes the issue.
Edit: visitor and Charles Bailey (in a comment) have the answer. The defaults are missing from your declaration of the function, so as far as the compiler is concerned you are trying to call a 4-parameter function with 3 arguments. The & is not the problem.
For future reference: when James McNellis asked you for "the" declaration of your function, he meant the declaration which is visible in the translation unit making the call. In your pastebin code, the definition is not visible in that translation unit, and the compiler cannot reach in to a completely different .cpp file and realise that the function is supposed to have parameter defaults. In C++, default values are set up in the calling code, for reasons to do with how calling conventions work.

Having seen the code, the defaults should be given in the header and not in the implementation file.
When you are compiling "monkeycard.cpp", the compiler has only the information in the headers to work with. The compiler has no idea that blit_image has default arguments, and therefore cannot match the function to call.

I suspect that the function isn't declared properly.
There needs to be a prototype inside the class display scope such as:
void blit_image(SDL_Surface* img, int x=0, int y=0, SDL_Rect* clip=NULL);
When you pass an int & parameter (such as any named variable of type int) to an int argument, the value of the int & is copied into the new object of type int. The difference in types implies a conversion which entails a copy which implements pass-by-value. That is just how the C++ formalism works.

The error message you see is nothing else than a specific convention, which that particular compiler uses to generate error messages in cases like that. Apparently, when the compiler is unable to resolve a function call, it generates an error message where every Lvalue argument is reported as having reference type and every Rvalue argument is reported as having non-reference type. This makes some sense, since references in C++ exist specifically for implementing the concept of run-time-bound Lvalue. In fact, it might even turn out that this is exactly how the overload resolution is implemented internally in that compiler.
As for the reason for the error: the function you are trying to call does not exist (or exists, but has a non-matching set of parameters).
P.S. You said in the comments that the matching function actually does exist. That would mean that there's either a problem with the visibility of the function declaration, or a problem with the code you posted being "fake" (i.e. it is not the code you were actually compiling).

Primitives are not reference types in C++.
How do you know that it's the int& that's the cause for the error? The error simply says that the signature is in error. I'd recommend going back and checking the method signature to see what the root cause is.

Related

Can variables be used in function call in ellipsis functions in C++

For this function that takes variable number of arguments,
void func(int count, ...) // ellipsis function
{
// function definition
}
Can a function call be made like follows :
int a{};
double b{};
string c{};
func(3,a,b,c); // using actual variables instead of fixed values in function call
My question is when an ellipsis function is called does it always has to be just fixed values like func(3,5,2.7,"Hi") or can variables be supplied in the function call like so func(3,a,b,c)?
Note that passing classes like std::string, with non-trivial copy constructor or nontrivial move constructor or non-trivial destructor, may not be supported and has "implementation-defined" semantics. You have to check your compiler documentation on how such classes are passed or check if they are supported at all.
Can variables be used in function call in ellipsis functions in C++
Yes.
Can a function call be made like follows
Yes.
when an ellipsis function is called does it always has to be just fixed values like func(3,5,2.7,"Hi")
No.
can variables be supplied in the function call like so func(3,a,b,c)?
Yes.
Can you suggest any reference so I can do some research on it?
https://en.cppreference.com/w/cpp/language/variadic_arguments https://en.cppreference.com/w/cpp/utility/variadic https://eel.is/c++draft/expr#call-12
And in C++ you should strongly prefer: https://en.cppreference.com/w/cpp/language/parameter_pack , because of type safety.
Though ellipsis gives us some useful functionality, it is quite dangerous to use them. When using ellipsis, the compiler does not check the type of arguments passed to the function. So the compiler does not throw any error if arguments are of different types. Even if pass string, double, or bool type values are passed to the average() function it returns return an unexpected value, the compiler does not throw any error.
Source : https://www.geeksforgeeks.org/ellipsis-in-c-with-examples/

Explicitly passing *this in C++

While reading about *this, I saw:
When a nonstatic member function is called for an object, the compiler
passes the object's address to the function as a hidden argument.
Then I tried:
#include <iostream>
class MyClass
{
int myVar;
public:
MyClass(const int& val) : myVar{val} {}
// int getVar(MyClass* this) <-- Error: expected ',' or '...' before 'this'
int getVar()
{
return this->myVar;
}
};
int main()
{
MyClass obj(22);
// std::cout << obj.getVar(&obj); <-- Error: no matching function
// std::cout << MyClass::getVar(&obj); <-- Error: no matching function
std::cout << obj.getVar();
return 0;
}
Why am I not able to access the hidden argument? Is it called 'hidden' because of that?
Are only compilers allowed to do this? Can't we explicitly mention *this in the function signature?
The closest answer I've found before asking this is this. But I tried that way and still got the error. Could I get an explanation of those error messages? Because, if the compiler actually modifies those function signatures to contain *this then that should have worked, isn't it?
Are only compilers allowed to do this?
Precisely. That's why it's called hidden: It's something that the compiler does on your behalf, but which is hidden from the C++ code that uses it.
The compiler must pass the this pointer to the member function somehow, but it does not need to tell you how it does it. It could compile the code to the equivalent of MyClass::getVar(&obj), passing the this pointer in the same way that it would pass the argument for the C function free(foo). Or it might use a different mechanism that is totally incompatible with non-member argument passing. What it does under the hood is defined by the platform's Abstract Binary Interface standard (ABI), which is not part of the C++ language standard. What happens under Windows could be vastly different from what happens under Linux, and Linux on ARM could be different from Linux on X86, etc.
That said, you can take a look at what actually happens by telling your compiler to produce the assembly code. For gcc, the incantation would be
g++ -S -Os interestingCode.cpp
This will produce a .s file that contains how g++ actually translated your code.
obj.getVar(&obj)
This version cannot compile because the getVar() member function is not declared to take any parameters.
MyClass::getVar(&obj)
This version is using the syntax to access a static function but getVar() is not static, nor does it accept any parameters.
Note: The obj.getVar() call works because it is specifying which object instance to use (i.e., the obj. part) to execute the member function and is conceptually how the member function is passed the this pointer.
When you are doing obj.getVar() it is already explicitly specified the pointer *this=&obj and passed implicitly to getVar. It is not hidden. It is explicitly passed leftside of the function. You can use obj.getVar() or ptrObj->getVar() but in C++ is not allowed to use such construction getVar(thisptr). Hidden means the variable named this is nowhere declared, but you can use inside the function.

decltype(function) as class member

I have:
int foo(int x) { return x+1; }
struct Bar {
decltype(foo) operator();
};
int main() {
Bar bar;
printf("%d\n",bar(6));
}
which results in the slightly startling compiler error message (g++ 4.6.1):
error: declaration of 'operator()' as non-function
When changing the member name to
decltype(foo) blubb;
and using it results in a linker error:
undefined reference to `Bar::blubb(int)'
Is this expected behaviour?
It seems that you want to "copy" the signature of another function to create a function with the same signature. Since decltype(foo) is indeed the type of the function (and not a pointer to that function, which would be decltype(&foo) and would lead to a pointer declaration), you can use it to declare a function with the same signature as another function.
As indicated by the linker error:
undefined reference to `Bar::blubb(int)'
this will already work fine with your compiler. However it seems that gcc did not yet fully implement this part of the standard, as it will not accept the syntax for the same thing with a function call operator. Clang btw. will happily accept it and the link then errors out with
undefined reference to `Bar::operator()(int)'
Your question about why that linker error exists indicates a misunderstanding of what decltype really does.
It will just evaluate to a type, not more. The definition of blubb is in no way tied to the definition of foo. This might be clearer when writing it like
typedef decltype(foo) x;
x blubb;
You can now alternatively typedef x to be explicitly the function type, which will not in any way change what blubb is. You still need to define it. And since there is no syntax to define it using decltype, you explicitly have to write it as
int Bar::operator()(int) {
...
}
which will likely and unfortunately defeat the purpose/benefit of using decltype for the declaration, as it will not allow you to automatically "copy" a signature.
This is a wild guess based on observing your usage of printf here:
printf("%d\n",bar(6));
This lets me assume you really want the return type of the function, not the type of the function. If so, then you use decltype wrong. You get the return type of the function by "simulating" the usage of the function, i.e.
decltype(foo(0)) operator() (int);
should be the right thing for you. Otherwise, if that was not your attention, you are skating on thin ice by giving a function type (and not function return type) to the %d specifier.
Generally, the meaning of decltype is: decltype(#) gives the static type of the expression #.
This should work.
I just used it here to capture whatever gobbledygook std::bind was going to give me:
class RiceFadingModel::Impl
{
public:
Impl(double K, double A)
: //...
_M_re{system_now()},
_M_rd{_M_nu, _M_sigma},
_M_gen{std::bind(_M_rd, _M_re)}
{ }
private:
//...
std::default_random_engine _M_re;
/// The underlying Rice distribution.
__gnu_cxx::__rice_distribution<double> _M_rd;
/// The variate generator built from the pseudo-random number engine and the Rice distribution.
decltype(std::bind(_M_rd, _M_re)) _M_gen;
};
This works like a charm on gcc-4.7. Now that I think about it I built it on mingw with gcc-4.5 too.

Defining a function with different signature

Today I discovered that it is possible to declare a function in a header with one signature, and implement it in the source file with different (similar) signature. For example, like this :
// THE HEADER example.hpp
#ifndef EXAMPLE_HPP
#define EXAMPLE_HPP
int foo( const int v );
#endif
// THE SOURCE FILE example.cpp
#include "example.hpp"
int foo( int v ) // missing const
{
return ++v;
}
Is this allowed? Or is this the compiler's extension (I am using g++ 4.3.0) ?
EDIT
I am compiling with pedantic and maximum possible warning level, and I am still not getting a warning or an error.
For the purposes of determining a function signature, any top level const qualifier is ignored. This is because it does not affect function callers. Function parameters are passed by value in any case so the function cannot affect the arguments passed in.
The top level const does affect the body of the function. It determines whether or not the parameter can be changed in the body of the function. It is the same function as the declaration though.
So yes, it is legal and the declaration and definition refer to the same function and not an overload.
Standard reference: 8.3.5 [dcl.fct] / 3: "[...] The type of a function is determined using the following rules. [...] Any cv-qualifier modifying a parameter type is deleted. [...] Such cv-qualifiers affect only the definition of the parameter within the body of the function; they do not affect the function type. [...]"
Since int is a basic value type, the const modifier does not have any effect here. No matter what you do to your int in the function, this will never be seen by the caller.
You can't do this with int&. In that case, the presence or absence of const is really relevant for the caller, since the int referred to could be modified.

Why isn't it possible to have an anonymous object as argument in a function argument list? C++

For example:
struct test
{};
void thing(test())
{}
int main()
{
thing(test());
}
This code would give me error; however, the next example won't give me error:
void thing(int())
{}
int main()
{
thing(int());
}
My main question is, why the first example isn't possible and the second one is? Ultimately, both test and int are types, so I can't think why declaring an anonymous object of test in the thing function argument list isn't possible whereas declaring an anonymous object of type int in the thing function argument list is.
It is possible; it's just that you're doing it wrong.
Here is a declaration of a function taking an unnamed parameter of type test:
void thing(test);
Here is a declaration of a function taking an unnamed parameter of type pointer-to-function-returning-test:
void thing(test());
You want the former, not the latter.
That your second code example works is actually a magical oddity, stemming from the fact that int() is 0 is a valid null pointer constant, which may be used to initialise a function pointer; the example breaks as soon as you swap int() for some other integer, or if you run the code in a completely compliant C++14 compiler (because C++14 made it so that 0 but not int() is a valid null pointer constant).