I like to create a registry of templated classes adressed through their polymorphic anonymous base-class. In order to construct these classes I need to store the type of the used template class in the base-class. I woulod like to make the design slim and pass the template class in the constructor of the baseclass through a custom templated constructor.
However my code fails, and i cannot figure out what the correct formulation would be. Any help appriciated:
#include <vector>
#include <string>
#include <typeinfo>
#include <memory>
class Store_Base {
const std::string stored_type_name_;
protected: //ctor
template<class Tstored>
Store_Base() : stored_type_name_(typeid(Tstored).name()) {};
protected: // dtor
virtual ~Store_Base() = default;
public:
std::string get_type_name() const {return stored_type_name_;}
};
template <class Tstored>
class Store : public Store_Base {
const Tstored stored_;
public: //ctor
Store(const Tstored stored)
: Store_Base<Tstored>(), stored_(stored) {}; // !!! compile-error
public:
Tstored get_stored() const {return stored_;}
};
int main() {
std::vector<std::unique_ptr<Store_Base>> my_vec;
my_vec.emplace_back(std::make_unique< Store<int> >(42));
my_vec.at(0)->get_type_name(); // >>> i
((Store<int>*)(my_vec.at(0).get()))->get_stored(); // >>> 42
return 0;
}
This
Store(const Tstored stored)
: Store_Base<Tstored>()
is wrong, because it attempts to initialize the base class Store_Base<Tstored>, but Store_Base is not a template. The base class to be initialized is Store_Base not Store_Base<Tstored>.
The way to call a templated constructor is to have the template argument deduced. See here C++ template constructor.
You can use a tag to enable deduction:
#include <vector>
#include <string>
#include <typeinfo>
#include <memory>
template <typename T>
class Tag{};
class Store_Base {
const std::string stored_type_name_;
protected: //ctor
template<class Tstored>
Store_Base(Tag<Tstored>) : stored_type_name_(typeid(Tstored).name()) {};
protected: // dtor
virtual ~Store_Base() = default;
public:
std::string get_type_name() const {return stored_type_name_;}
};
template <class Tstored>
class Store : public Store_Base {
const Tstored stored_;
public: //ctor
Store(const Tstored stored)
: Store_Base(Tag<Tstored>{}), stored_(stored) {}; // !!! compile-error
public:
Tstored get_stored() const {return stored_;}
};
int main() {
std::vector<std::unique_ptr<Store_Base>> my_vec;
my_vec.emplace_back(std::make_unique< Store<int> >(42));
my_vec.at(0)->get_type_name(); // >>> i
((Store<int>*)(my_vec.at(0).get()))->get_stored(); // >>> 42
return 0;
}
Note that I didn't change more than necessary and that this code still fails to compile due to the destructor of Store_Base being protected, ie std::unique_ptr cannot access it.
Related
Below is an implementation of the above question.
#include <iostream>
#include <map>
class Data {
int val;
};
template<class T>
class Test {
public:
Test(){};
private:
typename T::container _data;
};
class FunTest:public Test<FunTest> {
public:
typedef std::map<uint16_t, FunTest > container;
FunTest():Test(){}
};
int main()
{
FunTest object;
std::cout << "Hello World!\n";
}
I tried the above but I get the error
Error C2039 'container': is not a member of 'FunTest' Temp
Any insight on why this gives an error is much appreciated.
According to user17732522
Test will instantiate the template specialization before
container is declared, so T::container cannot use it.
So I guess one solution could be to move the typedef to Test class as a protected variable.
#include <iostream>
#include <map>
template<class T>
class Test {
public:
Test() {};
protected:
typedef std::map<uint16_t, T> container;
private:
typename container _data;
};
class FunTest :public Test<FunTest> {
public:
FunTest() :Test() {}
//Test<FunTest>::container c; access here as well if needed
};
int main()
{
FunTest object;
std::cout << "Hello World!\n";
}
I am trying to understand the behavior of "Type Erasure" by using std::make_shared. The basic idea is to use a class Object to wrap some different classes, such as class Foo and class Bar.
I write the following code, and it does work.
// TypeErasure.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual std::string getName() const = 0;
};
template< typename T >
struct Derived : Base
{
public:
explicit Derived(const T&& t) : objD(t) {}
std::string getName() const override
{
return objD.getName();
}
private:
T objD;
};
class Object
{
public:
template <typename T>
explicit Object(T&& t)
: objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}
std::string getName() const
{
return objPtr->getName();
}
std::shared_ptr<const Base> objPtr;
};
void printName(std::vector<Object> vec)
{
for (auto v: vec) std::cout << v.getName() << std::endl;
}
class Bar
{
public:
std::string getName() const
{
return "Bar";
}
};
class Foo
{
public:
std::string getName() const
{
return "Foo";
}
};
int main()
{
std::vector<Object> vec{Object(Foo()), Object(Bar())};
printName(vec);
}
but when I change "struct Derived : Base" into "class Derived : Base", it shows the following error.
error: no matching function for call to 'std::shared_ptr::shared_ptr(std::shared_ptr)'|
The code is as following.
// TypeErasure.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual std::string getName() const = 0;
};
template< typename T >
class Derived : Base
{
public:
explicit Derived(const T&& t) : objD(t) {}
std::string getName() const override
{
return objD.getName();
}
private:
T objD;
};
class Object
{
public:
template <typename T>
explicit Object(T&& t)
: objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}
std::string getName() const
{
return objPtr->getName();
}
std::shared_ptr<const Base> objPtr;
};
void printName(std::vector<Object> vec)
{
for (auto v: vec) std::cout << v.getName() << std::endl;
}
class Bar
{
public:
std::string getName() const
{
return "Bar";
}
};
class Foo
{
public:
std::string getName() const
{
return "Foo";
}
};
int main()
{
std::vector<Object> vec{Object(Foo()), Object(Bar())};
printName(vec);
}
What is the root cause of this error?
Is it about the difference between class and struct?
Is it because class is a reference and struct is a value?
The only real difference between a class and a struct in C++ is that, for a struct, the default member access and inheritance is public, whereas, for a class, the default is private.
So, to make your code work for the class Derived template, just make its inheritance of Base public:
template< typename T >
class Derived : public Base { // public inheritance
public:
//...
Such public inheritance gives the Derived class access to the Base class constructors.
Alternatively, to make your struct template case fail – most likely with the exact same error message(s) – you can make its inheritance of Base private:
template< typename T >
struct Derived : private Base { // private inheritance - fails to compile!
public:
//...
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last month.
Improve this question
I have a registry for lambda functions associated with a specific CommandId, where the registered function is supposed to create a concrete instance of a command executor class and supply it with some data:
CommandId.h
#include <cstdint>
enum class CommandId : uint16_t {
Command1 ,
Command2 ,
};
Registry.h
#include <map>
#include <functional>
#include <string>
#include "CommandId.h"
class Registry
{
public:
static std::map<CommandId,std::function<void (std::string)>>&
GetCommands() {
static std::map < CommandId, std::function<void(std::string)>>
theFunctionRegistry;
return theFunctionRegistry;
}
};
Now my idea was to provide concrete command implementations as derived classes from a CRTP template base, that provides a static member of itself just for the purpose of registering an associated lambda function (because the workflow for calling the derived classes will be just boilerplate code):
CommandBase.h
#include "CommandId.h"
#include "Registry.h"
// The general command execution interface
struct ICommand {
virtual void Execute(const std::string& data) = 0;
virtual ~ICommand() {}
};
template<typename Derived, CommandId CmdId>
class CommandBase : public ICommand
{
public:
virtual ~CommandBase() {}
void Register() {}
protected:
// Dummy function to avoid abstract instantiations, should probably throw
void Execute(const std::string& data) override {
}
// Protected constuctor meant for concrete command classes
CommandBase(int& derivedRef) : derivedRef_(&derivedRef) {}
// The static member that should perform the registation automagically
static CommandBase<Derived, CmdId> registryAdder_;
// This constructor is meant to be accessed from the above static member
// instantiation only, and just register the lambda function
CommandBase() : derivedRef_(nullptr) {
// Register a lambda function that ususe a concrete Derived instance
Registry::GetCommands()[CmdId] = [](const std::string& data) {
Derived derivedInstance;
CommandBase<Derived, CmdId>* der = static_cast<CommandBase<Derived, CmdId>*>(&derivedInstance);
// Manipulate the derived instances data and execute
*(der->derivedRef_) = 42;
der->Execute(data);
};
}
// Provides access to the derived class instances data members and allows manipulation
int* derivedRef_;
};
template<typename Derived, CommandId CmdId>
CommandBase<Derived, CmdId> CommandBase<Derived, CmdId>::registryAdder_;
I thought that accessing the static registryAdder_ member of the base would force the compiler to provide an instantiation, but that doesn't happen.
Here's a trial for Command1 and Command2
<h3>Command1.h</h3>
#include "CommandBase.h"
class Command1 : public CommandBase<Command1, CommandId::Command1>
{
public:
typedef CommandBase<Command1, CommandId::Command1> BaseClass;
friend class BaseClass;
public:
Command1(CommandId) {
BaseClass::registryAdder_.Register();
}
virtual ~Command1() override {}
private:
Command1() : BaseClass(member_)
{
BaseClass::registryAdder_.Register();
}
void Execute(const std::string& data) override {
}
private:
int member_;
};
Command2.h
#include "CommandBase.h"
class Command2 : public CommandBase<Command2, CommandId::Command2>
{
public:
typedef CommandBase<Command2, CommandId::Command2> BaseClass;
friend class BaseClass;
public:
Command12CommandId) {
BaseClass::registryAdder_.Register();
}
virtual ~Command1() override {}
private:
Command2() : BaseClass(member_)
{
BaseClass::registryAdder_.Register();
}
void Execute(const std::string& data) override {
}
private:
int member_;
};
I was hoping that the line
BaseClass::registryAdder_.Register();
in the constructors would force the instantiation of the BaseClass::registryAdder_ static base class member. But it obviously doesn't, and the compiler just strips it away:
#include <iostream>
#include "Command1.h"
#include "Command2.h"
#include "Registry.h"
int main()
{
std::cout << "There are " << Registry::GetCommands().size() << " registered commands." << std::endl;
return 0;
}
Output:
There are 0 registered commands.
Now my question is:
How can I force the compiler to instantiate those static base class members from the CommandBase template class?
I've done some research of course, but these Q&A's didn't really satisfy me:
How to force a static member to be initialized?
Force template static member instantiation
Explicit template static member instantiation in a derived class
... and maybe more
I decided to reopen the question and self answer based on Yakk's fixes. Seems to be a more common problem (see here for example)
Yakk's example solved it:
#include <cstdint>
enum class CommandId : uint16_t {
Command1 ,
Command2 ,
};
#include <map>
#include <functional>
#include <string>
//#include "CommandId.h"
class Registry
{
public:
static std::map<CommandId,std::function<void (std::string)>>&
GetCommands() {
static std::map < CommandId, std::function<void(std::string)>>
theFunctionRegistry;
return theFunctionRegistry;
}
};
// #include "CommandId.h"
// #include "Registry.h"
// The general command execution interface
struct ICommand {
virtual void Execute(const std::string& data) = 0;
virtual ~ICommand() {}
};
template<typename Derived, CommandId CmdId>
class CommandBase : public ICommand
{
public:
virtual ~CommandBase() {}
void Register() {}
protected:
// Dummy function to avoid abstract instantiations, should probably throw
void Execute(const std::string& data) override {
}
// Protected constuctor meant for concrete command classes
CommandBase(int& derivedRef) : derivedRef_(&derivedRef) {}
// The static member that should perform the registation automagically
static CommandBase<Derived, CmdId> registryAdder_;
// This constructor is meant to be accessed from the above static member
// instantiation only, and just register the lambda function
CommandBase() : derivedRef_(nullptr) {
// Register a lambda function that ususe a concrete Derived instance
Registry::GetCommands()[CmdId] = [](const std::string& data) {
Derived derivedInstance;
CommandBase<Derived, CmdId>* der = static_cast<CommandBase<Derived, CmdId>*>(&derivedInstance);
// Manipulate the derived instances data and execute
*(der->derivedRef_) = 42;
der->Execute(data);
};
}
// Provides access to the derived class instances data members and allows manipulation
int* derivedRef_;
};
template<typename Derived, CommandId CmdId>
CommandBase<Derived, CmdId> CommandBase<Derived, CmdId>::registryAdder_;
// #include "CommandBase.h"
class Command1 : public CommandBase<Command1, CommandId::Command1>
{
public:
typedef CommandBase<Command1, CommandId::Command1> BaseClass;
friend class CommandBase<Command1, CommandId::Command1>;
public:
Command1(CommandId) {
BaseClass::registryAdder_.Register();
}
virtual ~Command1() override {}
private:
Command1() : BaseClass(member_)
{
BaseClass::registryAdder_.Register();
}
void Execute(const std::string& data) override {
}
private:
int member_;
};
// #include "CommandBase.h"
class Command2 : public CommandBase<Command2, CommandId::Command2>
{
public:
typedef CommandBase<Command2, CommandId::Command2> BaseClass;
friend class CommandBase<Command2, CommandId::Command2>;
public:
Command2(CommandId) {
BaseClass::registryAdder_.Register();
}
virtual ~Command2() override {}
private:
Command2() : BaseClass(member_)
{
BaseClass::registryAdder_.Register();
}
void Execute(const std::string& data) override {
}
private:
int member_;
};
#include <iostream>
//#include "Command1.h"
//#include "Command2.h"
//#include "Registry.h"
int main()
{
std::cout << "There are " << Registry::GetCommands().size() << " registered commands." << std::endl;
return 0;
}
One needs to make use of these static instances in the derived classes.
Let's assume we have something like this: An Interface for some class Foo ( 'FooInterface' ) and a container class Bar that contains derived classes from 'FooInterface'.
Now I forward a typelist of the types of the derived classes ( 'FooOne', 'FooTwo' ) to the container class and it stores an instance of them in a 'boost::hana::tuple' subsequent to a small type computation ( 'FooTuple' ).
Now how do I initialize the tuple elements with a dereferenced this-pointer, depending on the size of 'FooList' ?
MCVE (Wandbox)
#include <iostream>
#include <boost/hana.hpp>
namespace hana = boost::hana;
template <typename FooList>
class Bar;
template <typename FooList>
class FooInterface
{
public:
FooInterface(Bar<FooList>& bar) {}
public:
virtual void foo() = 0;
};
class FooOne;
class FooTwo;
using MyFooList = decltype(hana::tuple_t<FooOne, FooTwo>);
class FooOne final
: public FooInterface<MyFooList>
{
public:
FooOne(Bar<MyFooList>& bar)
: FooInterface(bar)
{}
public:
void foo() override
{
std::cout << "FooOne!\n";
}
};
class FooTwo final
: public FooInterface<MyFooList>
{
public:
FooTwo(Bar<MyFooList>& bar)
: FooInterface(bar)
{}
public:
void foo() override
{
std::cout << "FooTwo!\n";
}
};
template <typename FooList>
class Bar
{
public:
using FooTuple = typename decltype(hana::unpack(FooList(), hana::template_<hana::tuple>))::type;
FooTuple foos{ *this, *this };
};
int main()
{
Bar<MyFooList> b;
b.foos[hana::int_c<0>].foo();
b.foos[hana::int_c<1>].foo();
}
Output :
FooOne!
FooTwo!
hana::replicate is your friend.
template <typename FooList>
class Bar {
...
using FooTuple = ...;
FooTuple foos;
Bar() : foos(hana::replicate<hana::tuple_tag>(*this, hana::size_c<N>)) {}
};
Now, you have to be careful cause that'll make a copy of each *this when creating a tuple in replicate. If you want references instead, use reference_wrapper like this:
foos(hana::replicate<hana::tuple_tag>(std::ref(*this), hana::size_c<N>))
and then make sure that the constructor of each thing in FooTuple can be constructed from a reference_wrapper (which is the case if they take a reference).
Not sure if this is the simplest way - but you might try std::index_sequence to do that:
template <typename FooList>
class Bar
{
static constexpr size_t fooListSize = decltype(hana::size(std::declval<FooList>()))::value;
template <std::size_t ...I>
Bar(std::index_sequence<I...>) : foos{(I, *this)...} {}
public:
using FooTuple = typename decltype(hana::unpack(FooList(), hana::template_<hana::tuple>))::type;
Bar() : Bar(std::make_index_sequence<fooListSize>{}) {}
FooTuple foos;
};
Basically I have a class let's say Parameter that has a get and set variable.
I also have a base class let's say Vehicle that has a method registerParameter(...) that takes a pointer to function member as getter and a pointer to function member as setter. This method is then supposed to write those two pointers into an object of the parameter class and throws this object into a vector.
And last but not least we have a derived class let's say Car and we call registerParameter(...) with the string "color" as parameter name and a getter and setter from this derived class.
Example in code:
Parameter file
#ifndef BASE_H
#define BASE_H
#include "base.h"
class Parameter
{
std::string (Base::*get)();
void (Base::*set)(std::string);
};
#endif
Base file
#ifndef PARAMETER_H
#define PARAMETER_H
#include <vector>
#include "parameter.h"
class Base
{
public:
std::vector<Parameter> list;
void registerNew(std::string (Base::*get)(), void (Base::*set)(std::string))
{
Parameters parameter;
parameter.get = get;
parameter.set = set;
list.push_back(parameter);
}
};
#endif
Derived file
class Derived
{
public:
Derived derived()
{
registerNew(&getColor, &setColor);
}
std::string getColor()
{
return this->color;
}
std::string setColor(std::string newColor)
{
this->color = newColor;
}
private:
std::string color;
};
I've been thinking about this for days now and I really need the solution until friday evening.
You cannot do what are trying:
The types std::string (Base::*)() and std::string (Derived::*)() are very different. std::string (Derived::*)() cannot be auto converted to std::string (Base::*)().
Take the following scenario.
struct Base
{
int foo() { return 10; }
};
struct Derived : Base
{
int bar() { return 20; }
};
int main()
{
Base base;
int (Base::*bf)() = &Base::foo;
(base.*bf)(); // Should be able to call Base:foo(). No problem.
bf = &Derived::bar; // This is a compiler error. However, if this were allowed....
(base.*bf)(); // Call Derived::bar()?? That will be a problem. base is not an
// instance of Derived.
}
Update
You can do something like:
#include <string>
#include <vector>
class Base;
// Create a base class Functor that provides the interface to be used by
// Base.
struct Functor
{
virtual ~Functor() {}
virtual std::string get(Base& base) = 0;
virtual void set(Base& base, std::string) = 0;
};
// Create a class template that implements the Functor interface.
template <typename Derived> struct FunctorTemplate : public Functor
{
// typedefs for get and set functions to be used by this class.
typedef std::string (Derived::*GetFunction)();
typedef void (Derived::*SetFunction)(std::string);
// The constructor that uses the get and set functions of the derived
// class to do itw work.
FunctorTemplate(GetFunction get, SetFunction set) : get_(get), set_(set) {}
virtual ~FunctorTemplate() {}
// Implement the get() function.
virtual std::string get(Base& base)
{
return (reinterpret_cast<Derived&>(base).*get_)();
}
// Implement the set() function.
virtual void set(Base& base, std::string s)
{
(reinterpret_cast<Derived&>(base).*set_)(s);
}
GetFunction get_;
SetFunction set_;
};
class Base
{
public:
std::vector<Functor*> functorList;
void registerFunctor(Functor* functor)
{
functorList.push_back(functor);
}
};
class Derived : public Base
{
public:
Derived()
{
// Register a FunctorTemplate.
registerFunctor(new FunctorTemplate<Derived>(&Derived::getColor,
&Derived::setColor));
}
std::string getColor()
{
return this->color;
}
void setColor(std::string newColor)
{
this->color = newColor;
}
private:
std::string color;
};
Your base class should know the derived class. That sounds complex but the problem has been solved already:
template<typename DERIVED> class Base
{
public:
class Parameter {
std::string (DERIVED::*get)();
void (DERIVED::*set)();
};
private:
std::list<Parameter> list;
// ...
};
class Derived : public Base<Derived> // !!!
{
registerNew(&Derived::getColor, &Derived::setColor);
};
This solution is known as the Curiously Recurring Template Pattern (CRTP).