I am trying to pass a function as an argument to a template class - the objective is that then I can pass any function as a argument and achieve different functionality:
int A()
{
return 0;
}
void Test() {
auto B2 = B<int(*A)()>(&A);
}
int main()
{
Test();
}
But I am getting compilation issue:
$ c++ -std=c++14 try.cpp
try.cpp: In function 'void Test()':
error: cast from 'int (*)()' to 'int' loses precision [-fpermissive]
auto B2 = B<int(*A)()>(&A);
^ ^
How can I instantiate class B with a function of any return type and accepting any argument and resolve the compilation?
You should remove the function name A in the template parameter in the line auto B2 = ... such that it looks like this:
auto B2 = B<int(*)()>(A);
The name is not a part of the type specifier, and the type is the only thing the compiler looks for when trying to instantiate the class template. You can use this snippet to refer to the name of the function and let the compiler deduce its type:
auto B2 = B<decltype(&A)>(A);
Note that you can optionally drop the & before A when passing it to the constructor of B (doesn't work for decltype(&A) though), as it's implicitly converted to a function pointer.
Function name is not part of the type of a function pointer.
This line:
auto B2 = B<int(*A)()>(&A);
should be:
auto B2 = B<int(*)()>(&A);
Related
I am trying to write a class which it's objects are able to be added together and be assigned to another existed object like this(a1 is an initialized object):
numcpp<float> a2 = a1;
a2 = a1 + 2;
but I get this error:
test.cpp: In function ‘int main()’:
test.cpp:81:13: error: cannot bind non-const lvalue reference of type ‘numcpp<float>&’ to an rvalue of type ‘numcpp<float>’
a1 = a2d2 + 2;
~~~~~^~~
In file included from test.cpp:1:
numcpp.h:283:6: note: initializing argument 1 of ‘void numcpp<T>::operator=(numcpp<T>&) [with T = float]’
void numcpp<T>::operator=(numcpp &obj)
^~~~~~~~~
Then I tried this code:
numcpp<float> a2 = a1;
&a2 = a1 + 2;
And I got:
test.cpp: In function ‘int main()’:
test.cpp:81:16: error: lvalue required as left operand of assignment
&a1 = a2d2 + 2;
^
Here are operator functions I used in my test code:
template <class T>
numcpp<T> numcpp<T>::operator+(T n)
{
numcpp<T> obj(i, j, k);
for (int x = 0; x < size; x++){
obj.set(array[x] + n, x);
}
return obj;
};
template <class T>
void numcpp<T>::operator=(numcpp &obj)
{
for (int x = 0; x < size; x++){
this->set(obj.get(x), x);
}
return;
};
The problem is in your operator= overload you want to take a non-const reference.
Your expression a2 = a1 + 2 a2 is an lvalue, a1 is also an lvalue but the 2 is an rvalue and it will be implicitly converted to a numcpp<int> object. Then the a1 and the converted 2 is added together, which is an rvalue. After that you try to call the operator= which takes a non-const reference, which cannot bind to an rvalue. Change the operator= to take a const reference.
You should check what an lvalue and an rvalue is.
But even after the const modification your code will not compile, because you must specify the template parameter of the numcpp object in the equals overload.
For more info look up templates on cppreference, but if you are a beginner don't start with templates or at least don't dive too deep at first because it is kinda a sub programing language of C++ and it can be daunting even for experienced people.
That second example you tried is not compiling because you take the memory address of a1, which is by definition is an rvalue and you try to modify it.
code:
#include <iostream>
using namespace std;
struct item
{
int f1() {}
double f2() {}
static int g1() {}
static double g2() {}
void f0();
};
void item::f0()
{
auto c1 = reinterpret_cast<decltype(f2)>(f1);
auto c2 = reinterpret_cast<decltype(g2)>(g1);
auto c3 = reinterpret_cast<decltype(&f2)>(f1);
auto c4 = reinterpret_cast<decltype(&g2)>(g1);
}
int main()
{
cout << "Hello world!" << endl;
return 0;
}
error message:
main.cpp|17|error: invalid use of non-static member function|
main.cpp|18|error: invalid cast from type ‘int (*)()’ to type ‘double()’|
main.cpp|20|error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say ‘&item::f2’ [-fpermissive]|
main.cpp|20|error: invalid use of member function (did you forget the ‘()’ ?)
my question:
The member functions passed as arguments will automatically convert to pointer, so i try casting the argument to a pointer, but still failed.
I don't understand why non-static member function doesn't work in all
situation.
You need to cast the return value of f1, not f1. Use:
auto c1 = reinterpret_cast<decltype(f2())>(f1());
^^ Call the function
Make similar changes to the other lines.
I misunderstood what you were trying to do. The following should work:
auto c1 = reinterpret_cast<decltype(&item::f2)>(&item::f1);
auto c2 = reinterpret_cast<decltype(&g2)>(g1);
auto c3 = reinterpret_cast<decltype(&item::f2)>(&item::f1);
auto c4 = reinterpret_cast<decltype(&g1)>(g2);
f1 is a non-staticmember function. You can call it using f1(). However, without the function call syntax, non-static member functions don't automatically decay to a member function pointer. To get a member function pointer of the struct, you'll need to use &item::f1.
please have a look at this program and the error it is generating:
#include <iostream>
using namespace std;
class A
{
public:
virtual void f(){}
int i;
};
class B : public A
{
public:
B(int i_){i = i_;} //needed
B(){} //needed
void f(){}
};
int main()
{
//these two lines are fixed(needed)
B b;
A & a = b;
//Assignment 1 works
B b1(2);
b = b1;
//But Assignment 2 doesn't works
B b2();
b = b2; // <-- error
}
upon compilation, I get the following error:
$ g++ inher2.cpp
inher2.cpp: In function ‘int main()’:
inher2.cpp:32:10: error: invalid user-defined conversion from ‘B()’ to ‘const B&’ [-fpermissive]
inher2.cpp:14:6: note: candidate is: B::B(int) <near match>
inher2.cpp:14:6: note: no known conversion for argument 1 from ‘B()’ to ‘int’
inher2.cpp:32:10: error: invalid conversion from ‘B (*)()’ to ‘int’ [-fpermissive]
inher2.cpp:14:6: error: initializing argument 1 of ‘B::B(int)’ [-fpermissive]
Can you help me find the problem? thank you
Your "B b2();" is the 'vexing parse' problem of C++ (see here - the 'most vexing parse' takes the ambiguous syntax further).
It looks to the C++ compiler that you are declaring a function (a pre-declaration).
Check it out:
int foo(); //A function named 'foo' that takes zero parameters and returns an int.
B b2(); //A function named 'b2' that takes zero parameters and returns a 'B'.
When you later do:
b = b2;
It looks like you are trying to assign a function (b2) to a variable (b).
To call a constructor with zero parameters, call it without the parentheses and you'll be fine:
B b2;
For more information, see:
Understanding 'most vexing parse' - why allow ambiguous syntax?
Most vexing parse: why doesn't A a(()); work?
B b2();
It is a function declaration, not a variable declaration!
The function name is b2 which takes no argument, and returns object of type B.
Search for vexing parse in C++.
So I have a custom class Foo which has been registered as a metatype using the Q_DECLARE_METATYPE(Foo) macro at the end of the class definition.
I can set items within a list, check to see if canConvert, but when I try to actually make an item of type Foo things fail at compile time.
Using QVariant passed in from a QModelIndex &index:
Foo item(index.data(Qt::DisplayRole).value<Foo>())
fails with the following error(s):
no matching function for call to 'namespace::Foo::Foo(namespace::Foo)'
In instantiation of 'T qvariant_cast(const Foo&) [with T = namesapce::Foo]':
required from 'T QVariant::value() const [with T = namespace::Foo]'
no matching function for call to 'namespace::Foo::Foo(const namespace::Foo &)'
no matching function for call to 'namespace::Foo::Foo(const namespace::Foo&)'
no matching function for call to 'namespace::Foo::Foo(const namespace::Foo)'
In member function 'T QVariant::value() const [with T = namespace::Foo]'
all from file qvariant.h
What am I doing wrong here?
My class has the following constructors:
Foo::Foo(const Foo &)
Foo::Foo()
The header is as follows:
namespace a {
namespace b {
class Foo {
explicit Foo();
explicit Foo(const Foo &a);
...
};
} // b
} // a
Q_DECLARE_METATYPE(a::b::Foo)
As Dan Milburn suggested, removing the explicit keywords solved the problem. It appears an implicit conversion was occurring in the value call, therefore having only explicit constructors prevented this.
8.3.5/8 Functions [dcl.fct] says
[...] Functions shall not have a return type of
type array or function, although they may have a return type of type pointer or reference to such things. [...]
Why so explicit of a rule? Is there some syntax that would even allow returning a function as opposed to a function pointer?
Am I miss-interpreting the quote?
typedef void (*fp)();
void foo(){}
fp goo()
{
return foo; //automatically converted to function pointer
}
This is quite a contrived example of a function trying to return a function:
void foo() { }
template<typename T>
T f() { return foo; }
int main(){
f<decltype(foo)>();
}
This is the error I get from Clang 3.2:
Compilation finished with errors:
source.cpp:7:5: error: no matching function for call to 'f'
f<decltype(foo)>();
^~~~~~~~~~~~~~~~
source.cpp:4:3: note: candidate template ignored: substitution failure
[with T = void ()]: function cannot return function type 'void ()'
T f() { return foo; }
~ ^
1 error generated.
Is there some syntax that would even allow returning a function as opposed to a function pointer?
A syntax? Sure there is:
using fun = int (int);
fun function_that_returns_a_function();
That doesn’t compile because the rule in §8.3.5/8 forbids it. I don’t know why the rule specifically exists – but consider that the type “function” doesn’t have any size so you cannot create objects of function type in C++.
I know this probably does not answer your question completely but it does so partially
You can return a function from another function (that's what lambdas are)
std::function<int (int)> retLambda() {
return [](int x) { return x; };
}