Compilation issues with smart pointer-based CRTP idiom - c++

I'm trying to compile a minimal working example for the CRTP example given in this blog post, which is based on smart pointers.
Based on the code example, I've written two files, a header and source.
Header (crtp.h):
#include <memory>
class Cloneable
{
public:
virtual ~Cloneable() {}
std::shared_ptr<Cloneable> clone() const
{
return std::shared_ptr<Cloneable>(this->clone_raw());
}
private:
virtual Cloneable* clone_raw() const = 0;
};
template <typename Derived, typename Base>
class CloneInherit<Derived, Base>: public Base
{
public:
std::shared_ptr<Derived> clone() const
{
return std::shared_ptr<Derived>(static_cast<Derived*>(this->clone_raw()));
}
private:
virtual CloneInherit* clone_raw() const override
{
return new Derived(*this);
}
};
class Concrete: public CloneInherit<Concrete, Cloneable> {};
Source (example.cc):
#include <memory>
#include "crtp.h"
int main()
{
std::shared_ptr<Concrete> c = std::make_shared<Concrete>();
std::shared_ptr<Concrete> cc = c->clone();
Cloneable* p = c.get();
std::shared_ptr<Cloneable> pp = p->clone();
return 0;
}
Compilation of this code fails with the following error:
In file included from example.cc:3:
./crtp.h:18:7: error: explicit specialization of non-template class 'CloneInherit'
class CloneInherit<Derived, Base>: public Base
^ ~~~~~~~~~~~~~~~
./crtp.h:29:16: error: no matching constructor for initialization of 'Concrete'
return new Derived(*this);
^ ~~~~~
./crtp.h:33:7: note: in instantiation of member function 'CloneInherit<Concrete, Cloneable>::clone_raw' requested here
class Concrete: public CloneInherit<Concrete, Cloneable>
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:4411:26: note: in instantiation of member function 'std::__1::__shared_ptr_emplace<Concrete, std::__1::allocator<Concrete> >::__shared_ptr_emplace' requested
here
::new(__hold2.get()) _CntrlBlk(__a2, _VSTD::forward<_Args>(__args)...);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:4775:29: note: in instantiation of function template specialization 'std::__1::shared_ptr<Concrete>::make_shared<>' requested here
return shared_ptr<_Tp>::make_shared(_VSTD::forward<_Args>(__args)...);
^
example.cc:7:42: note: in instantiation of function template specialization 'std::__1::make_shared<Concrete>' requested here
std::shared_ptr<Concrete> c = std::make_shared<Concrete>();
^
./crtp.h:33:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'const CloneInherit<Concrete, Cloneable>' to 'const Concrete' for 1st argument
class Concrete: public CloneInherit<Concrete, Cloneable>
^
./crtp.h:33:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'const CloneInherit<Concrete, Cloneable>' to 'Concrete' for 1st argument
class Concrete: public CloneInherit<Concrete, Cloneable>
^
./crtp.h:33:7: note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided
2 errors generated.
There are ways I can fix these errors. I can delete the <Derived, Base> specialization from the declaration for CloneInherit to make the first error go away and change the definition of clone_raw() function of CloneInherit to
virtual CloneInherit* clone_raw() const override
{
return new CloneInherit(*this);
}
but I'm not sure if this will get the same results as what the post originally intended.

There are indeed several typo in his post:
Fixed version:
#include <memory>
class cloneable
{
public:
virtual ~cloneable() {}
std::unique_ptr<cloneable> clone() const
{
return std::unique_ptr<cloneable>(this->clone_impl());
}
private:
virtual cloneable * clone_impl() const = 0;
};
template <typename Derived, typename Base>
class clone_inherit : public Base
{
public:
std::unique_ptr<Derived> clone() const
{
return std::unique_ptr<Derived>(static_cast<Derived*>(this->clone_impl()));
}
private:
clone_inherit* clone_impl() const override
{
return new Derived(*static_cast<const Derived*>(this));
}
};
class concrete : public clone_inherit<concrete, cloneable>
{
};
int main()
{
std::unique_ptr<concrete> c = std::make_unique<concrete>();
std::unique_ptr<concrete> cc = c->clone();
cloneable * p = c.get();
std::unique_ptr<cloneable> pp = p->clone();
}
Demo

Related

C++ - Overriding Virtual Templated Member Functions

In this example:
class MyClass
{
public:
MyClass(int i);
};
template<typename T>
class Base
{
public:
virtual std::unique_ptr<T> createObj()
{
return std::make_unique<T>();
}
};
class Derived : public Base<MyClass>
{
public:
std::unique_ptr<MyClass> createObj() override
{
return std::make_unique<MyClass>(4);
}
};
int main()
{
Derived instance;
auto createdObj = instance.createObj();
}
I cannot call the derived createObj() function. It seems the code is trying to still call the base version with the MyClass instance which leads to compilation failures since the required construction arguments are not passed. Why does this not work as a normal overriden function and call the derived version that does supply the correct arguments?
You misinterpreted the error. The error message is:
In file included from <source>:1:
In file included from /opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/memory:83:
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/bits/unique_ptr.h:962:34: error: no matching constructor for initialization of 'MyClass'
{ return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
^
<source>:15:21: note: in instantiation of function template specialization 'std::make_unique<MyClass>' requested here
return std::make_unique<T>();
^
<source>:19:7: note: in instantiation of member function 'Base<MyClass>::createObj' requested here
class Derived : public Base<MyClass>
^
<source>:6:5: note: candidate constructor not viable: requires single argument 'i', but no arguments were provided
MyClass(int i);
^
<source>:3:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
class MyClass
^
<source>:3:7: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided
1 error generated.
Base<MyClass> tries to default construct a MyClass but MyClass has no default constuctor. Even if you are not trying to call Base<MyClass>::createObj the method must be valid because it is instantiated as part of Base<MyClass>.
In other words, merely instantiating Base<MyClass> will fail. Not calling the method does not make it less of an error.
I am not entirely sure whats the aim, but if you make the method pure virtual in Base your code compiles without issues:
#include <memory>
class MyClass
{
public:
MyClass(int i) {}
};
template<typename T>
class Base
{
public:
virtual std::unique_ptr<T> createObj() = 0;
};
class Derived : public Base<MyClass>
{
public:
std::unique_ptr<MyClass> createObj() override
{
return std::make_unique<MyClass>(4);
}
};
int main()
{
Derived instance;
auto createdObj = instance.createObj();
}
Alternatively you could provide a default contructor for MyClass.

Inheritance, Copy Constructors and Implicit Typecasting

I have a derived class which I want to be able to construct using the copy constructor where the argument is an instance of the base class.
I am sure this should be possible in C++. Here is an example:
#include <string>
class Base
{
public:
friend
void swap(Base& l, Base& r)
{
using std::swap;
swap(l.a, r.a);
}
Base()
: a{1}
{
}
Base(const int a)
: a{a}
{
}
virtual
~Base()
{
}
Base(const Base& base)
: a{base.a}
{
}
Base(Base&& base)
: Base()
{
swap(*this, base);
}
Base& operator=(Base base)
{
swap(*this, base);
return *this;
}
protected:
int a;
};
class Derived : public Base
{
protected:
std::string b;
};
int main()
{
Base base(2);
Derived derived(base);
}
The error (g++ main.cpp) is:
main.cpp: In function ‘int main()’:
main.cpp:71:31: error: no matching function for call to ‘Derived::Derived(Base&)’
class Derived derived(base);
^
main.cpp:57:7: note: candidate: Derived::Derived()
class Derived : public Base
^~~~~~~
main.cpp:57:7: note: candidate expects 0 arguments, 1 provided
main.cpp:57:7: note: candidate: Derived::Derived(const Derived&)
main.cpp:57:7: note: no known conversion for argument 1 from ‘Base’ to ‘const Derived&’
main.cpp:57:7: note: candidate: Derived::Derived(Derived&&)
main.cpp:57:7: note: no known conversion for argument 1 from ‘Base’ to ‘Derived&&’
So the compiler doesn't know how to convert from an instance of Base to Derived implicitly.
I thought that this should be legal in C++. Do I require an explicit conversion statement?
What are you doing doesn't make much sense by itself because Base is not a sub-type of Derived so it can't be used as its replacement/substitution, however you could attempt to give it sense (same as with initialization from any other type) by writing a converting constructor:
class Derived : public Base
{
public:
Derived(const Base &bs) : Base(bs), b("constructed from base") {}
protected:
std::string b;
};
This would first initialize Derived Base part from bs and then init the string b with some value (though you can leave it out if you want it to be default-inited to empty string).
https://godbolt.org/z/GMELW_
Yes, you need to cast explicitely from Base to Derived. Every Mercedes is a car, but not every car is a Mercedes.
this statement Derived derived(base); or to simplify B b(A()); do an implicit conversion of type A to type B, which is legal only if class B inherit directly or indirectly from Class A.
Why ? Because class B could contains new information, in your case a string b, and a cast don't "append" information.
There is a simple way of solving this problem: By pulling the Base constructor into the scope of Derived.
This can be done with the using statement:
class Derived : public Base
{
public:
using Base::Base; // Pulls in the Base class constructors into the scope of Derived
...
};
I found what I was looking for (I couldn't remember the name so couldn't google it before). However this technique actually doesn't work due to the fact that I am using inheritance. (Or at least I don't know how to make it work.)
Type conversion operator:
Base::operator Derived()
{
Derived derived;
derived.a = a;
return derived;
}
This doesn't actually compile because the compiler doesn't know what Derived is. (Since Derived inherits from Base.) I don't know if it is possible to make this work by separating the compilation units.

Initializing base class const member in most derived class

In the below code, I initialize const member of Base class in the most derived class Grandchild.
class Base {
public:
Base(int x_) : x(x_) {}
private:
const int x;
};
class Child : public virtual Base {
public:
virtual ~Child() = 0;
};
class Grandchild : public virtual Child {
public:
Grandchild() : Base(42) {}
};
Child::~Child() {}
int main() {
Grandchild gc;
}
In case of virtual inheritance, the Base class constructor is called by the most derived class. Hence, I expect the code to compile successfully.
clang 4.0 compiles it successfully, whereas gcc 4.9.2 emits the following error:
In constructor 'Grandchild::Grandchild()':
16:27: error: use of deleted function 'Child::Child()'
9:7: note: 'Child::Child()' is implicitly deleted because the default definition would be ill-formed:
9:7: error: no matching function for call to 'Base::Base()'
9:7: note: candidates are: 3:5: note: Base::Base(int)
3:5: note: candidate expects 1 argument, 0 provided
1:7: note: constexpr Base::Base(const Base&)
1:7: note: candidate expects 1 argument, 0 provided
1:7: note: constexpr Base::Base(Base&&)
1:7: note: candidate expects 1 argument, 0 provided
What does the standard say about this?
It seems there was a change in the C++ standard clarifying the requirements of generated constructors for virtual base classes. See CWG257. As far as I understand this text your situation should be allowed. Prior to the change the situation was unclear.
This change was voted into the Working Paper in October 2009, i.e., it should be applicable to compiling with C++11.

How to inherit some candidates of polymorphic function?

I want to define a function in a base class and a function with the same name and another signature in a subclass like this:
class A {
public:
void foo () {}
};
class B : public A {
public:
void foo(int x) {}
};
int main() {
B b;
b.foo();
}
But it causes compile error: no matching function for call to ‘B::foo()’.
If I comment foo definition in class B, it compiles.
How to solve the problem?
What I really want is to define a polymorhic interface in a base class and redefine semantic in child classes.
UPD: Thanks, the answers worked for this example. But it doesn't seem to work with templates:
sort.h
...
class Sort {
public:
template <typename TArr>
static TArr& sort(TArr& array) { return sort(array, array.size()); }
};
class BubbleSort : public Sort { // add inheritance
public:
using Sort::sort;
template <typename TArr>
static TArr& sort(TArr& array, size_t len) {
...
}
};
test.cpp
...
int main () {
...
std::array<int, 5> test_array {3, 2, 5, 1, 4};
BubbleSort::sort(test_array)
...
}
When I run this, I get:
sort.h: In instantiation of ‘static TArr& Sort::sort(TArr&) [with TArr = std::array<int, 5ul>]’:
test.cpp:9:30: required from here
sort.h:17:47: error: no matching function for call to ‘Sort::sort(std::array<int, 5ul>&, std::array<int, 5ul>::size_type)’
static TArr& sort(TArr& array) { return sort(array, array.size()); }
^
sort.h:17:16: note: candidate: template<class TArr> static TArr& Sort::sort(TArr&)
static TArr& sort(TArr& array) { return sort(array, array.size()); }
^
sort.h:17:16: note: template argument deduction/substitution failed:
sort.h:17:47: note: candidate expects 1 argument, 2 provided
static TArr& sort(TArr& array) { return sort(array, array.size()); }
Why does it happen?
UPD: Got that.
Without virtual, the A::foo() doesn't define a polymorphic interface.
Anyway, you can make A::foo() visible via B with a using declaration:
class B : public A {
public:
using A::foo;
void foo(int x) {}
};
This provides polymorphism to the extent that you accept function overloading as polymorphism--i.e., A::foo() and B::foo() form an overload set, and the compiler chooses which to call based on the parameter(s) you pass (if any), the same way as if B contained two overloaded functions (with the same signatures as the existing A::foo and B::foo).
But it causes compile error: no matching function for call to ‘B::foo()’
Try using-declaration:
class A {
public:
void foo() {}
};
class B : public A {
public:
using A::foo;
void foo(int x) {}
};
What I really want is to define a polymorphic interface in a base class and redefine semantic in child classes.
Well, you should make the base class function virtual an have the same parameters when override it. Otherwise, how the subclass function is supposed to be called via a reference/pointer to the base class?
Function f from the derived class simply hides all the functions with the same name from the base class.
To solve it you can use a using-declaration:
class B : public A {
public:
using A::foo;
void foo(int x) {}
};

no matching function for call to ..constructor

I am trying to compile a code that involves inheritance.
#include "MapEntityClass.h"
class RectangularEntityClass:public MapEntityClass
{
public:
void drawOnMap(MapClass *mapObj) const;
protected:
};
The parent class is MapEntityClass, which does not have a default constructor, but has a value constructor. When I compile, I get the following error:
RectangularEntityClass.h: In constructor ‘RectangularEntityClass::RectangularEntityClass()’:
RectangularEntityClass.h:12:7: error: no matching function for call to ‘MapEntityClass::MapEntityClass()’
class RectangularEntityClass:public MapEntityClass
^
RectangularEntityClass.h:12:7: note: candidates are:
In file included from main.cpp:1:0:
MapEntityClass.h:32:5: note: MapEntityClass::MapEntityClass(const PixelLocationClass&, const ColorClass&)
MapEntityClass(
^
MapEntityClass.h:32:5: note: candidate expects 2 arguments, 0 provided
Any idea what is wrong?
In inheritance, the subclass need not have a constructor only if parent class doesn't have a constructor or only default constructor.
In any case, if parent class happens to have a parameterized constructor, the subclass should have a parameterized constructor which should invoke the parent class constructor.
Example:
class A {
int aVal;
public:
A(int);
};
A::A(int aVal)
{
this->aVal = aVal;
}
class B : public A {
int bVal;
public:
B(int, int)
};
B::B(int aVal, int bVal) : A(aVal)
{
this->bVal = bVal;
}