Conditions to declare function deleted by c++ - c++11

ALL,
What are the conditions where the compiler itself declares the function deleted?
Consider following:
class Foo
{
public:
Foo();
virtual void func1() = 0;
virtual void func2() = 0;
virtual bool func3();
}
class Bar : public Foo
{
public:
Bar(int param1);
virtual void func1() override;
virtual void func2() override;
virtual bool func3() override;
}
class Baz
{
public:
Baz(std::unique_ptr<Foo> &foo)
{
m_foo = foo;
}
private:
std::unique_ptr<Foo> m_foo;
}
I am getting a compiler error on the assignment (MSVC 2019):
attempting to reference a deleted function
This is compiled with C++11.
TIA!

The error seems to come from the line m_foo = foo
unique_ptr cannot be copied thus unique_ptr& operator=(const unique_ptr&) is deleted.
Unique pointers are about exclusive ownership. Thus, if you want to transfer ownership to baz, you will need to move the unique_ptr.
For example:
Baz(std::unique_ptr<Foo> foo) : m_foo{std::move(foo)}
{
}
For the conditions a compiler declares a special member deleted (by declared, we mean regular declaration or =default or =deleted):
if a destructor or copy op or assignment op is declared then move operators are marked as deleted,
if only one of the move operator is declared, the other one is marked as deleted,
if a move copy op or a move assignment op is declared, the regular copy/assignment op are marked as deleted.

Related

const member function apparently allows to change state of object

class Foo
{
public:
Foo(int& cnt) : cnt_(cnt) {}
void test() const
{
cnt_ = 0;
}
protected:
int& cnt_;
};
int cnt;
int main()
{
Foo foo(cnt);
foo.test();
}
The above code compiles. The test function is const, however we are allowed
to change the value of cnt_. If "cnt_" is not a reference then compiler
gives an error as expected. However if "cnt_" is a reference like above,
why doesn't compiler give an error ? We are still changing the state of the
object "Foo" inside a const member function, isn't it ?
The member cnt_, declared as:
int& cnt_;
is a reference, and inside the member function:
void test() const;
the const-qualification is applied to the members, i.e.: the reference, and not to the object referenced. Therefore, the object being referenced can still be modified through that reference, even inside a const member function, like the one above.
Note that, references can't be assigned after initialization anyway, so it really doesn't change what you can do with that reference.
Perhaps a pointer analogy will help.
Let's say you have:
struct Foo
{
Foo(int* cnt) : cnt_(cnt) {}
void test1() const
{
*cnt_ = 0;
}
void test2(int* p) const
{
cnt_ = p; // Not allowed
}
int* cnt_;
};
In test1, you are not changing cnt_. You are changing the value of cnt_ points to. That is allowed.
In test2, you are changing cnt_. That is not allowed.
In your case, you are not changing cnt_ to reference another object. You are changing the value of the object cnt_ references. Hence, it is allowed.

Member function pointer on derived class

I have some trouble with a member pointer in a CRTP template.
Here the code it is a virtual call function who call a member function pointer on a crtp derived class.
class KeyboardHandler {
public:
virtual void keyPressed(KeyboardKey) = 0;
virtual void keyReleased(KeyboardKey) = 0;
KeyboardHandler & operator=(const KeyboardHandler &) = default ;
};
template<class T>
class KeyboardHandlerOpti : public KeyboardHandler {
public:
using KeyboardCallback = void (T::*)(KeyboardKey key, KeyboardStatus status) ;
KeyboardHandlerOpti(KeyboardCallback defaultCallback);
virtual void keyPressed(KeyboardKey key) override final;
virtual void keyReleased(KeyboardKey key) override final ;
std::vector<KeyboardCallback> mCallbackPressed ;
std::vector<KeyboardCallback> mCallbackReleased ;
KeyboardHandlerOpti & operator=(const KeyboardHandlerOpti &) = default ;
private:
KeyboardCallback mDefaultCallback ;
};
class GlfwDefaultKeyboardHandler :
public KeyboardHandlerOpti<GlfwDefaultKeyboardHandler> {
public:
GlfwDefaultKeyboardHandler() ;
GlfwDefaultKeyboardHandler & operator=(const GlfwDefaultKeyboardHandler &) = default ;
private:
//This is type of KeyboardCallback
void drawKey(KeyboardKey key, KeyboardStatus status) ;
} ;
The class GlfwDefaultKeyboardHandler is initialized with drawKey as KeyboardHandlerOpti::mDefaultCallback
template<class T>
KeyboardHandlerOpti<T>::KeyboardHandlerOpti(KeyboardCallback defaultCallback) :
mDefaultCallback(defaultCallback),
mCallbackPressed(getKeyboardKeyCount(), mDefaultCallback),
mCallbackReleased(getKeyboardKeyCount(), mDefaultCallback) {
}
and Callback are called with
template<class T>
void KeyboardHandlerOpti<T>::keyPressed(KeyboardKey key) {
KeyboardCallback c = mCallbackPressed[getKeyValue(key)] ;
(dynamic_cast<T *>(this)->*c)(key, KeyboardStatus::ePressed) ;
//(this->*c)(key, KeyboardStatus::ePressed) ;
}
Unfortunately I have a segfault and I am not able to understand why. I found some interesting value in debug. I can see at the construction of KeyboardHandlerOpti that I have things that I don't really understand.
defaultCallback value is 0x4b7578 and debuger can tell the name of the function but mDefaultCallback is "0x7ef360, this adjustment 96" and it is the same value in both vectors.
So if someone can explain to me why do I have the segfault I would be very happy.
Memebers are initialized in the order they are listed in the class definition, not in the order they appear in the initializer list in the constructor. In KeyboardHandlerOpti constructor, mCallbackPressed and mCallbackReleased are initialized first, and only then mDefaultCallback is assigned a value. So you stuff your vectors full of random garbage. Formally, your program exhibits undefined behavior.
Make it
template<class T>
KeyboardHandlerOpti<T>::KeyboardHandlerOpti(KeyboardCallback defaultCallback) :
mCallbackPressed(getKeyboardKeyCount(), defaultCallback),
mCallbackReleased(getKeyboardKeyCount(), defaultCallback),
mDefaultCallback(defaultCallback)
{
}
That is, use defaultCallback to populate the vectors. Moving mDefaultCallback to the end is not technically necessary, it just makes the order in the list match the order in which initializers are actually executed (I believe some compilers warn when initializers are in the "wrong" order).

Linker refers to, supposedly, undefined reference to vtable

I am trying to use an abstract class to represent a common base for subtypes. However, it (the linker it seems) keeps moaning about vtables and undefined references no matter what I do. Judging by the error messages, the problem must be related to the destructors in some way. Wierdldy enough, it keeps talking about a
"undefined reference to 'AbstractBase::~AbstractBase()'"
in child.cpp which makes no sense.
Like last time, I can't actually show my code, so here is an example that in essence does the same thing:
First the abstract class, "AbstractBase.h":
#ifndef ABSTRACTBASE
#define ABSTRACTBASE
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
}
#endif
The child that uses the abstractbase, "child.h":
#ifndef CHILD
#define CHILD
class child : public AbstractBase
{
public:
~child() override;
}
#endif
The implementation in "child.cpp":
#include "child.h"
child::~child()
Obviously there are far more functions, but in essence that's how my real class's destructors look.
After scouring the web for ways of using abstract classes in C++, I am about to give up. As far as I can tell from those sources, this is the way to do it. You declare your abstracts class's destructor virtual, so any call to it will include the child. And the child's destructor is simply marked override. There shouldn't be anything else to it.
Have I missed something truly fundamental here?
PS: added MCVE:
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
};
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
~child() override
{}
}
int main (argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
I should add that the errors I now get are not entirely identical, while the original ones look like this:
undefined reference to 'vtable for AbstractBase': In function
AbstractBase:~AbstractBase()': Undefined reference to 'vtable for
AbstractBase': Undefined reference to 'typeinfo for AbstractBase':
Collect2:error:ld returned 1 exit status
You need to define a destructor for every class, otherwise you cannot destroy objects of that class (which includes member objects and base sub-objects):
class AbstractBase
{
public:
virtual ~AbstractBase() = default;
}; // ^^^^^^^^^^^
Some alternative formulations:
User-defined:
struct AbstractBase {
virtual ~AbstractBase() {}
};
Pure-virtual, but defined:
struct AbstractBase {
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() = default;
This has the benefit of leaving the class abstract even if you have no other virtual member functions.
Combine the two:
struct AbstractBase {
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() {}
I thank you all for your assistance. I eventually stumbled upon a solution.
Apperently, having regular virtual functions in the abstract class causes these issues. I recreated both the fix and the error in my MCVE, observe:
Nonfunctional code:
class AbstractBase
{
public:
virtual void idiot();
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase()=default;
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
void idiot() override
{
}
~child() override
{
}
};
int main(int argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
Functional code:
class AbstractBase
{
public:
//virtual void idiot();
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase()=default;
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
/*void idiot() override
{
}*/
~child() override
{
}
};
int main(int argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
Notice the only change I made, was commenting out the virtual function idiot, and it's implementation in child.
From my point of view, this is illogical. That extra function should not cause problems.
Alternatively, and this is the true solution, one can make all virtual functions pure. This solves the problem.
I can only guess at what's going on here, it would seem it looks for the implementation of the non-pure functions in a AbstractBase.cpp, which ofcourse doesn't exist. The result is the talk about undefined references to vtables and typeinfo for said AbstractBase, it is right in stating that the virtual functions are indeed undefined. But it shouldn't care, the class is abstract.
My conclusion would be, provided this is intended functionality, that you do need to declare all functions pure if you are to use abstract classes in c++, even though logic dictates it would be unnecessary. At any rate, if it is indeed intended, then the compiler should warn the user. The current errormessages are completely useless.

how to use functor and function pointer together? unable to assign function to a function pointer

I am just trying out c++11. I want to demonstrate functor and function pointer in the same program but I keep getting an error.how to use functor and function pointer together? unable to assign function to a function pointer. unable to assign the function test1 and test2 to function pointer foo
cannot assign Functortest* to a void* is the error i am getting. what should i do, why am i not able to assign the function to the function pointer foo and foo1
#include<iostream>
#include<string>
using namespace std;
class Functortest{
public:
Functortest(){
//foo=void(*)();
//void(*foo1)(string);
}
void operator()(int option){
switch (option){
case 1:
void(*foo)();
foo=test1;
break;
case 2:
void(*foo1)();
foo = test2;
}
};
void test1(){
cout << "TEST1 CALLED";
}
void test2(string msg){
cout << "TEST2 CALLED msg: "<< msg;
}
private:
void *foo;
void *foo1;
/*void(*foo)();
void(*foo1)(string);*/
};
void main(){
Functortest funct;
funct(1);
funct(2);
}
The parashift C++ FAQ contains quite some information on how you can use member function pointers.
#include<iostream>
#include<string>
//using namespace std; // <-- better avoid `using namespace` at file scope
class Functortest {
public:
Functortest()
: foo(&Functortest::test1) // better use the mem-initializer-list
, foo1(&Functortest::test2) // to initialize members
{}
void operator()(int option){
switch (option){
case 1:
(this->*foo)();
foo = &Functortest::test1; // after the call?
break;
case 2:
(this->*foo1)("Hello World"); // need to pass an argument
//foo = &Functortest::test2; // <-- this won't work! (A)
break; // better always end with a break
}
};
void test1() {
std::cout << "TEST1 CALLED\n";
}
void test2(std::string msg) {
std::cout << "TEST2 CALLED msg: " << msg << "\n";
}
private:
void (Functortest::*foo)(); // declares a data member foo
void (Functortest::*foo1)(std::string); // declares a data member foo1
};
int main() { // NOT `void main`
Functortest funct;
funct(1);
funct(2);
}
On the line commented with // <-- this won't work! (A):
As you can see from the declarations of the data members foo and foo1, those two have different types:
foo is of the type void (Functortest::*)(), i.e. foo is a pointer to a member function of class Functortest, which takes no arguments and returns nothing. It is the same type as a pointer to the specific member function test1 of class Functortest.
foo1 is of the type void (Functortest::*)(std::string), i.e. foo1 is a pointer to a member function of class Functortest, which has a parameter of type std::string and returns nothing. It is the same type as a pointer to the specific member function test2 of class Functortest.
A function that takes no arguments cannot be called with an argument (trivial), similarly, a function that has a parameter cannot be called with no arguments. Therefore, the types of foo and foo1 are incompatible. For the same reason, you cannot assign a pointer to Functortest::test1 to a pointer to a member function [...] which takes an argument of type std::string.

Why does GCC not find my non-template function? ("no matching function for call to...")

In MSVC 2008, I have the following code:
class Foo {
// Be a little smarter about deriving the vertex type, to save the user some typing.
template<typename Vertex> inline void drawVertices(
Elements vCount, RenPrim primitiveType, PixMaterial *mtl, Vertex const *vertices)
{
this->drawVertices(vCount, primitiveType, mtl, vertices, Vertex::VertexType);
}
virtual void drawVertices(
Elements vCount,
RenPrim primitiveType,
PixMaterial *mtl,
void const *vertices,
uint vertexType) = 0;
};
I use it something like:
struct RenFlexibleVertexPc
{
enum { VertexType = RenVbufVertexComponentsPc };
float x;
float y;
float z;
GraVideoRgba8 c; // Video format, not external!
};
PixMaterial *material;
struct Pc : RenFlexibleVertexPc
{
void set(Triple t, uint cl) { x = (float)t.x_; y = (float)t.y_; z = (float)t.z_; c = cl; }
} vpc[4];
...
Foo *renderer;
renderer->drawVertices(4, RenPrimTriangleFan, material, vpc);
This works fine in MSVC 2008 SP1. However, GCC (3.4 and 4.1,2) throws a "no matching function for call to function" error, apparently not seeing the template when there is a non-template function with more arguments.
Is GCC broken, or is my code broken, and if so, why?
There is no problem with overloading or inheritance:
#include <iostream>
#include <memory>
namespace {
struct A {
virtual void f()
{
std::cout<<"inside A's f()\n";
}
template <typename T> void f(T t)
{
std::cout<<T::i<<'\t';
this->f();
}
};
struct B : A {
void f()
{
std::cout<<"hello\t";
A::f();
}
};
struct C {
static const unsigned int i = 5;
};
struct D {
enum { i = 6 };
};
}
int main()
{
std::auto_ptr<A> b(new B());
b->f(C());
b->f(D());
}
Works correctly. On the other hand, the smallest example I can find that exhibits your problem does not have inheritance or overloading:
#include <iostream>
namespace {
struct A {
template<class C> void print(C c)
{
c.print();
}
};
}
int main()
{
struct B {
void print()
{
std::cout << "whee!\n";
}
};
A a;
B b;
a.print(b);
}
Note that if struct B is defined in a namespace (whether it's an unnamed namespace, or a completely different namespace, or the global namespace) instead of inside main() that this compiles without error.
I don't know enough of the standard to say if this is a bug, but it appears to be one. I've gone ahead and reported it to the GCC bug database.
And here's your answer from the GCC developers (from the link above): "Local classes cannot be template arguments."
So the code is broken. Not that it's a bad idea. In fact, C++0x removes this restriction.
I noticed the line
Note that the code works in GCC if I explicitly cast vpc to (RenFlexibleVertexPc *)
And since RenFlexibleVertexPc is not a local class this makes sense. However Pc is a local class/struct, so it is not allowed.
#OP: Specifying the template parameter is a valid approach.
renderer->drawVertices<RenFlexibleVertexPc>(4, RenPrimTriangleFan, material, vpc);
With Pete's additions, you code also compiles on Apple's GCC 4.0.1, so I suspect there's something your posted code is missing that's causing the problem.
#Max: GCC's treatment of your source is standard. Struct B is local to main(), so B (and thus main()::B::print()) is not visible outside main(). As you're probably aware, moving the definition of B outside of main() and it will compile.
The definition of VertexType is already in the code (an enum). Elements is an unsigned long. Note that the code works in GCC if I explicitly cast vpc to (RenFlexibleVertexPc *)
If it's an enum why pass an object of type array 4 of struct? What is RenFlexibleVertexPc? The last argument to drawVertices should either be a constant pointer to a Vertex object or a const* to an object of a class derived from Vertex.
Foo *renderer;
renderer->drawVertices(4, RenPrimTriangleFan, material, vpc);
You are calling a function on an uninitialized pointer. I hope this is not the real code. \

Resources