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.
Related
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);
Is there a way to disable conversion operators? Marking them "= delete" messes up other things.
Consider the following code:
class Foo
{
public:
Foo() :mValue(0) {}
~Foo() = default;
Foo(int64_t v) { mValue = v; }
Foo(const Foo& src) = default;
bool operator==(const Foo& rhs) { return mValue == rhs.mValue; }
/* after commenting these lines the code will compile */
operator int() const = delete;
operator int64_t() const = delete;
private:
int64_t mValue;
};
int main()
{
Foo foo1(5);
Foo foo2(10);
bool b1 = (foo1 == foo2);
bool b2 = (foo1 == 5);
}
This won't compile because gcc complains that the == operator is ambiguous:
test.cc: In function ‘int main()’:
test.cc:25:21: error: ambiguous overload for ‘operator==’ (operand types are ‘Foo’ and ‘int’)
bool b2 = (foo1 == 5);
^
test.cc:25:21: note: candidates are:
test.cc:25:21: note: operator==(int, int) <built-in>
test.cc:25:21: note: operator==(int64_t {aka long int}, int) <built-in>
test.cc:10:10: note: bool Foo::operator==(const Foo&)
bool operator==(const Foo& rhs) { return mValue == rhs.mValue; }
^
However, after commenting the conversion operators, the code will compile and run nicely.
The first question is: why do the deleted conversion operators create an ambiguity for the == operator? I thought they should disable implicit Foo -> int conversions but they seem to affect int -> Foo conversions which does not sound logic to me.
Second one: is there a way to mark the conversion operators deleted? Yes, by not declaring them - but I'm looking for a way that anyone in the future will see that those conversions are disabled by design.
Any use of a deleted function is ill-formed (the program will not
compile).
If the function is overloaded, overload resolution takes place first,
and the program is only ill-formed if the deleted function was
selected.
In you case programm can't select conversion becouse you have 3 variant
int -> Foo
Foo -> int
Foo -> int64
Second question:
you can leave it as it is, but always use explicit conversion for int
bool b2 = (foo1 == Foo(5));
Here's what I think is the crux of the matter:
[dcl.fct.def.delete]:
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.
...
A deleted function is implicitly an inline function ([dcl.inline]).
[class.member.lookup/4]:
If C contains a declaration of the name f, the declaration set
contains every declaration of f declared in C that satisfies the
requirements of the language construct in which the lookup occurs.
Even if you delete the function, you still declare it. And a declared function will participate in overload resolution. It's only when it's the resolved overload, that the compiler checks if it's deleted.
In your case, there is an obvious ambiguity when those function declarations are present.
g++ compiler complains about:
error: no matching function for call to ‘AddressSpace::resolve(ClassOne&, ClassTwo*&, ClassThree&) const’
note: candidates are: bool AddressSpace::resolve(ClassOne&, ClassTwo*, ClassThreer) <near match>
The code causing this error is
void Class::handler(ClassOne& objOne, ClassTwo& objTwo,
ClassThreer objThree) {
obj.getAddressSpaceObj().resolve(objOne, objTwo.pointer, objThree);
}
I digged into the code and found this error is caused by the reference type returned by getOtherObj() . I make it to return a const reference to the AddressSpace object in the class definition, see
const AddressSpace &getAddressSpaceObj(){
return addressSpace;
}
After I change this definition to return a normal reference,
AddressSpace &getAddressSpaceObj(){
return addressSpace;
}
the compiler doesn't complain about it any more. I wonder why this error is declared as parameter mismatching error? Why compiler didn't copy content as the parameters of function call but passed them as references?
If resolve does not have a const specifier then you can not call it on a const reference, so that would be consistent with changing it to be being non-const and having it now work. Here is a really trivial example:
#include <iostream>
class A
{
public:
void someFuncA() {};
void someFuncB() const {} ;
} ;
int main()
{
A
a1 ;
const A &aRef = a1 ;
a1.someFuncA() ;
// Below won't work because aRef is a const & but someFuncA() not const
//aRef.someFuncA() ;
// Below will work since someFuncB() is const
aRef.someFuncB() ;
}
Just for completeness sake, if you uncomment aRef.someFuncA() then the error you will receive will be similar to this:
19:19: error: no matching function for call to 'A::someFuncA() const'
19:19: note: candidate is:
6:12: note: void A::someFuncA() <near match>
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; };
}
I have the following code :-
class A : public B {
public:
_container (B* b) {
container_ = b;
}
private:
B* container_;
};
void foo(const A& a, const B& b) {
A new_a (a);
new_a._container(&b);
}
If I try to compile this using icpc12, I get :-
error: no instance of overloaded function "A::_container" matches the argument list
argument types are: (const B *)
object type is: A
new_a._container (&b);
Now, I understand that the first line of the error means there is some sort of type mismatch between the function being called and the function definitions available and I'm trying to narrow down the problem using the other two lines of the error message.
What do the second and third lines mean?
The function takes a non-const pointer as an argument, and you're passing a const pointer.