Meaning of class(*)() in gcc - c++

I'm having trouble understanding this compiler error. I wrote class(*)() in the post title because the class I am instantiating is called "opaque", but that name is not informative or relevant. It is a templatized Circular Buffer and some tests. I am using the opaque class to test the data structure with full class/struct types. I am also testing with primitives (int at the moment) and that test function does not give me this compiler error. There is more code than this, but I've provided what I think are the relevant sections.
The full code is here if you are interested.
gcc error:
tests.cpp: In function ‘bool opaque_fill_test(int)’:
tests.cpp:97:23: error: no matching function for call to ‘CircBuf<opaque>::remove(opaque (*)())’
tests.cpp:
struct opaque {
int id;
opaque(int n): id(n) {}
opaque operator=(const opaque &o) { this->id = o.id; }
};
opaque rcv();
CircBuf<opaque> c(size);
for (int i=0; i<size; i++) {
if ( c.remove(&rcv)) {
if (rcv.id != i ) {
cout << "wrong value: " << rcv << " "
<< "should be: " << i << endl;
return false;
}
} else {
cout << "remove fail at i=" << rcv << endl;
return false;
}
}
CircBuf.h:
template<typename T> class CircBuf {
...
template<typename T> bool CircBuf<T>::remove(T *t) {
...
*t = data[front];
...
if i declare an opaque* and pass that to remove instead:
opaque rcv();
opaque* p = &rcv;
for (int i=0; i<size; i++) {
if ( c.remove(p)) {
...
...
i get a similar error:
tests.cpp: In function ‘bool opaque_fill_test(int)’:
tests.cpp:96:16: error: cannot convert ‘opaque (*)()’ to ‘opaque*’ in initialization

If you have the declaration foo x();, the expression &x will actually be a function pointer assignable to something like foo *(y)(). The p variable in your last example isn't such a function pointer, but simply a pointer to an opaque struct. Thus you cannot assign the function pointer to that variable.
[edit]
Just remembered: maybe you meant to declare an opaque variable and initialize it using the default constructor. Leave out the parentheses then. It's a left-over syntax from C. You can only use the parentheses there if you actually put values in between to call a different constructor.

What you are doing with:
opaque rcv();
is that you are "declaring a function" with the name rcv having the return type opaque, and taking no arguments. Check this link
Drop the paranthesis:
opaque rcv;

You hit the most vexing parse.
if i declare an opaque* and pass that to remove instead:
opaque rcv();
That declares a function returning opaque, not a default-initialized opaque. Instead use opaque rcv; or opaque rcv = {};.
As for the error message, opaque (*)() is the type of a pointer to a function returning opaque. The name of the "function" was implicitly converted to a pointer when used for something besides a call.

Related

Invalid cast error in function template which return values depends on its generic type

I have the following function template
template<typename T>
T foo(){
if(std::is_same<T,int>::value){
return 1;
}
if(std::is_same<T,std::string>::value){
return "Hello";
}
}
I want to apply it like this:
int main(){
std::cout << foo<int>() << std::endl; // 1
std::cout << foo<string>() << std::endl; // "Hello"
}
If I try to compile my template the compiler throws the following error:
error: cannot initialize return object of type 'int' with an lvalue of type 'const char [6]'.
If I remove the second if statement everything compiles fine and I get the correct output therefore I guess the comparison std::is_same<T,int>::value works as intended.
It seems like the Compiler detects the type of T, checks if all return statements match it and throws the error because an std::string is not implicitly castable to int.
Has anyone a solution or another workaround to satisfy my intention?
EDIT
To explain my intention: I am writing a wrapper class for a database cursor class. As these cursors are usually defined it has several member functions like getInt() or getString(). My idea was to implement a generic get<T>() that uses the corresponding cursor member function that depends on T.
Forget the if statements and fully specialize the template function:
template<>
int foo<int>(){
return 1;
}
template<>
std::string foo<std::string>(){
return "Hello";
}
When you reference foo<int>, the compiler generates a function like the following from your template:
int foo<int>(){
if(true){
return 1;
}
if(false){
return "Hello";
}
}
Above code is ill-typed, because (as the compiler tells you) an int cannot be initialized with a C string (char const [N]). Sure, the corresponding return statement will never be reached, but that's something to be figured out by "dead code elimination", which is merely an optimization.
The solution "now" is shown in Dustin's answer, with C++17 we'll get if constexpr which is able to discard code paths the way you expected it:
template<typename T>
T foo(){
if constexpr (std::is_same<T,int>::value){
return 1;
}
if constexpr (std::is_same<T,std::string>::value){
return "Hello";
}
}

Assignment operator overload / retrieve function

I'm trying to retrieve an item from a BST for an assignment in class. Some of the provided code I am not allowed to alter. The instructor has created a retrieve function in the driver (which I can't change) that looks like this
static void retrieveItem(char *name)
{
Data const *data;
cout << ">>> retrieve " << name << endl << endl;
if (database->retrieve(name, data))
cout << *data << endl;
else
cout << "not found" << endl;
cout << endl;
}
The function it calls in the BST class looks looks like this (so far). I cannot change the arguments to the function call.
bool BST::retrieve(const char *key, Data const *& data) const
{
int rIndex = 0;
while (rIndex <= capacity)
{
if (strcmp(items[rIndex].data.getName(), key) == 0)
{
data = items[rIndex].data;
return true;
}
else if (strcmp(items[rIndex].data.getName(), key) < 0)
rIndex = (rIndex * 2) + 1;
else if (strcmp(items[rIndex].data.getName(), key) > 0)
rIndex = (rIndex * 2) + 2;
}
return false;
}
There is an array of structs called items that looks like this
struct Item
{
Data data; // the data instance must be specified this way, NOT as a pointer
bool isEmpty = true;
int loc = 0;
};
Item *items;
Finally I have the following assignment overload and copy constructors implemented for the data class (can't change the source file on this one)
Data::Data(const Data& source)
{
strcpy(this->name, source.name);
}
Data& Data::operator=(const Data& data2)
{
strcpy(this->name, data2.name);
return *this;
}
Please correct me if I'm wrong, but it seems like the goal of his retrieve function in the driver is to search for a data object using a key(name), and then copy it into the data argument sent to function. Unfortunately, the line
data = items[rIndex].data;
in my retrieve function doesn't work with a . or an ->]
I'm 90% sure the . is the correct way to access that, but I'm given the error "no suitable conversion type from 'Data' to 'const Data *' exists"
How else could I achieve this without using the assignment overload operator, or my implementation of the overload wrong?
bool BST::retrieve(const char *key, Data const *& data) const
The second argument is a reference to a pointer to const Data, so you must set it to a pointer to items[rIndex].data, not to its value.
Consider the following
void foo(int & out)
{
out = 42;
}
When it is called like so
// ...
int x = 0;
foo(x);
std::cout << x;
42 will be printed, because a reference to x was passed into the function. Your situation is a little different - you are passed a reference to a pointer, so that the caller can retrieve a pointer to the data in a similar way to the above, for example:
int x; // global
// ...
void foo(int *& out)
{
x = 42;
out = &x; // set out to pointer to x
}
int main()
{
int * ptr = nullptr;
foo(ptr); // foo will set ptr to the pointer to x
std::cout << *ptr; // prints 42
}
Again, 42 will be printed. Note the use of the unary ref, &, and deref, *, operators to get a pointer to x and dereference ptr to extract its value.
As an aside, it's not possible to tell how broken your implementation of Data::operator= is without seeing more of the class. As it stands it is broken because it is undefined behaviour to use strcpy on overlapping regions of memory - which will happen if someone tries to assign an object instance to itself (see strcpy). For cases other than self-assignment, it is only correct if the destination of the assignment always has enough space for the string in the source. Otherwise you will write to unallocated memory. Also, if there are any additional member variables, they will need copying too.

functor: wrapping std::function in a class

Say I am writing a library that should provide some default computing (function), but enables the user to provide his own, at compile-time.
For instance, say the library provides a function that returns his argument times 3, but the user can provide his own function.
Consider the following program (to be seen as a MWE):
float myFunction( float v ) // the function the user needs
{
return v*2;
}
int main()
{
FuncWrapper f;
cout << "default: " << f(2) << endl; // should print "6"
f.AssignFunction( myFunction );
cout << "now is: " << f(2) << endl; // should print "4"
}
So I have build a functor FuncWrapper that wraps a std::function, as proposed also here:
struct FuncWrapper
{
std::function<float(float)> foo; // the function used
float def( float v ) // the default behaviour member function definition
{
return v*3;
}
float operator()( float v ) // call of function
{
return foo(v);
}
void AssignFunction( float (*uf)(float) ) { foo = uf; }
// constructor: initializes to default function
FuncWrapper() : foo(&FuncWrapper::def) {}
};
On my machine (gcc 4.6.3) with -std=c++0x, I get non human-readable error messages, as stated in this other answer. For conveniency, the code is runnable here. Seems to be gcc 4.8, and it doesn't like the constructor (among other errors...):
main.cpp: In constructor 'FuncWrapper::FuncWrapper()':
main.cpp:27:64: error: no matching function for call to 'std::function<float(float)>::function(float (FuncWrapper::*)(float))'
Why is this assignment illegal ? I have searched for this topic, maybe wrong keyword, but didn't find anything relevant.
Any clue? Or a simpler solution, maybe without std::function but with a function pointer?
In your example code, you try to assign your member function to a std::function with signature float(float). These two are not compatible, since the member function has a different calling convention: it requires a this argument.
Make your default function static to avoid this.

double & and move function in C++

I would like to use parameter in C++ to store back whatever value/object.
In this example, I try to store the value from the global variable as a simplified example.
This code doesn't work,
int value = 20;
void returnPointer2(int* hello)
{
hello = &value;
}
// It changes nothing
int value2 = 100;
returnPointer2(&value2);
cout << value2 << endl;
as I needed double pointer.
void returnPointer3(int** hello)
{
*hello = &value;
}
int* vp2 = new int();
*vp2 = -30;
returnPointer3(&vp2);
cout << *vp2 << endl; // expects 20
I reminded of the reference, and I can use pointer reference to get the same result.
void returnPointer4(int* & hello)
{
cout << "value : " << value;
hello = &value;
}
int* vp3 = new int();
*vp3 = -130;
returnPointer4(vp3); // also expects 20, but much simpler to use
cout << "better : " << *vp3 << endl;
I tried with double &, and it compiles.
void returnPointer5(int&& hello)
{
cout << "value : " << value;
hello = value;
}
However, it doesn't compile with the input of integer variable.
int vp4 = 123;
returnPointer5(vp4); // also expects 20, but even more simpler to use
cout << "best : " << vp4 << endl;
This is an error message.
pointer_return.cpp:31:6: error: initializing argument 1 of 'void returnPointer5(int&&)'
void returnPointer5(int&& hello)
I happened to know about move, and it works with this code.
int vp4 = 123;
returnPointer5(move(vp4)); // also expects 20, but much simpler to see
cout << "best : " << vp4 << endl;
What's the magic/logic behind this move function?
There is a lot of stuff getting mixed in here, but to keep it simple I'll address your root question.
&& is nothing at all like **.
&& is an rvalue reference, while ** is a pointer to a pointer.
As a second point, you are declaring in your function name what you want to do: returnPointer4.
You want to have a pointer to an integer returned back. int*& is the correct syntax for having a reference to a pointer.
Reading over your question again, why don't you use the following:
int& returnGlobalReference() {
return value;
}
Then in your other function:
int& value2 = returnGlobalReference();
The first attempt makes the classic mistake of passing a pointer by value, modifying its address in the function and expecting what it points to to change.
As mentioned in the comments,
void returnPointer2(int* hello)
{
hello = &value; // don't do this, it only modifies what the
// pointer hello, which resides in the stack, points to
*hello = value; // do this instead. even though hello still resides in the
// stack, you're modifying the location that hello points to,
// which was your original intention
}
why do you want to pass pointers however? is the static variable not available when you call the function? (perhaps, different files?)
The magic of std::move is:
The actual declaration for std::move is somewhat more involved, but at its heart, it's just a static_cast to an rvalue reference.
Taken from here.
As Jeffery Thomas already said, a && is not a reference to a reference, but a reference to a rvalue.

Can we detect what function to call on fly from parameters given at runtime?

Say we have N function overrites, we receive argunments array, parsed it into some types (say first time we get int, string, string; second time we get int, int, int); Now we want to call for first set of arguments our call(int, string, string) while second time call(int, int, int). Can we detect which function to call on fly having arguments types array?
You can't do type choice in C++ at runtime. That is because C++ is one of the Strongly typed languages.
You could do something similar to what you are suggesting in e.g. Python -- where variables are happy to change their type during runtime.
You can do something close -- but not quite the same, with inherited and derived classes. If you have a superclass, you could have a "factory" function that returns a pointer to a superclass (containing a diff object depending on some input). Now if all the objects have the desired functionality implemented, you could call a function on the pointer. E.g.:
class Base{
virtual void functionality();
};
class Squirrel : public Base{
void functionality() {
std::cout << "I love hazelnuts!" << std::endl;
}
};
class Box : public Base{
void functionality() {
std::cout << "Stuff can be put in here!" << std::endl;
}
};
Base *factoryMethod(std::string someInput){
if (someInput == "1")
return new Squirrel();
else
return new Box();
}
int main(void){
std::cin >> input;
Base *object = factoryMethod(input);
object->functionality();
return 0;
}
You could simply write anoverloaded member function with the relevant params?
If you are receiving an unknown number of arguments and want to call the correct functions based upon them then you will need to some additional work. Perhaps have an enum as the first parameter which implies a parameter set e.g.:
enum eParamList
{
eParamList_START,
IntIntInt, // following data is 3 ints
IntIntChar, // following data is int, int, bool (only joking its a char)
eParamList_ENDS
}
Or something like this?
This is the low tech way of doing it. I don't know exactly what you mean by argument types array, but let's assume you are given some kind of vector called args, and you can determine if an element is a number or not, and convert the element into a number or string. Then, you can implement a loop like this one:
std::string s[3];
int n[3];
unsigned mask = 0;
for (int i = 0; i < args.size(); ++i) {
if (is_number(args[i])) {
mask |= (1U << i);
n[i] = get_number(args[i]);
} else {
s[i] = get_string(args[i]);
}
}
And then, switch on the mask:
switch (mask) {
case 0x01: call(n[0], s[1], s[2]); break;
case 0x07: call(n[0], n[1], n[2]); break;
default:
std::cout << "unhandled combination: " << mask << std::endl;
break;
}