Not sure if this question has been asked before. I am implementing a factory class. Every instance should inherit from a base class InstBase and should be initialized through a centralized factory.
class InstBase {
friend class Factory;
private:
InstBase() = default;
factory* factory;
}
class Factory {
template <typename Derived, typename... ArgsT>
InstBase* get(ArgsT&&... args) {
return new Derived(std::forward<ArgsT>(args)...)
}
}
class MyInst : public InstBase {
public:
MyInst(int a, int b) {...};
}
factory.get<MyInst>(1, 2);
As you can see in this example, the interface takes a Derived as a template and initialize an instance with user-defined argument list passed to the constructor of Derived. However, what I want to add here is assigning the pointer to the factory in which the instance is created. This can be done by:
template <typename Derived, typename... ArgsT>
InstBase* get(ArgsT&&... args) {
auto ptr = new Derived(std::forward<ArgsT>(args)...);
ptr->factory = this;
return ptr;
}
I felt this is a bit redundant because the base class InstBase is always created before the derived and can be only newed by the factory class. Is there any trick to achieve this goal without changing the interface of get? It doesn't make sense for me to ask user to attach another pointer to factory in the argument list (e.g., factory.get<MyInst>(1, 2, &factory)).
If you want to forbid the use of Factory as a type for the arguments, you can use something like this (C++11 compliant):
template<typename>
constexpr bool isBaseOf() { return false; }
template<typename T, typename U, typename... O>
constexpr bool isBaseOf() { return std::is_base_of<T, typename std::decay<U>::type>::value || isBaseOf<T, O...>(); }
Thus changing the factory method as it follows:
template <typename Derived, typename... ArgsT>
InstBase* get(ArgsT&&... args) {
static_assert(not isBaseOf<Factory, ArgsT...>(), "!");
return new Derived(std::forward<ArgsT>(args)...)
}
That said, I don't like it too much, for I won't use a class that does not let me use the parameters I want!!
Related
I have some kind of templated base class
template<typename Derived>
class Base { };
and want to store derived instances of it in a list.
For that I use a using derived_handle = std::unique_ptr<void, void(*)(void*) alias.
When I now add a derived instance to the list i cound use a static member function as deleter
class foo {
template<typename Derived, typename... Args>
void add_base(Args&&... args) {
auto derived = derived_handle{new Base{std::forward<Args>(args)..., &foo::_deleter<Derived>};
_derived.emplace_back(std::move(derived));
}
private:
template<typename Baser>
void _deleter(void* base) {
delete static_cast<Base*>(base);
}
std::vector<derived_handle> _derived{};
};
or a lambda
class foo {
template<typename Derived, typename... Args>
void add_base(Args&&... args) {
auto deleter = [](auto* derived){
delete static_cast<Derived*>(derived);
}
auto derived = derived_handle{new Base{std::forward<Args>(args)..., std::move(deleter)};
_derived.emplace_back(std::move(derived));
}
private:
std::vector<derived_handle> _derived{};
};
Are there any advantages/disadvantages of the lambda version I should be aware of?
Time for a frame challenge!
You've made some bad decisions in that code. Most people who use unique_ptr, even in a polymorphic context, don't need custom deleters at all. The only reason you do, is because of your type erasure, and that's only there because Base<A> and Base<B> are unrelated types.
If you really need Base<T>, have it inherit from an actual polymorphic (and non-templated) base class with a virtual destructor. Then you don't need unique_ptr<void> (a really bad code smell), and you can actually use your list in a type-safe manner.
I am trying to specialize a template this way:
class PropertyBase
{
public:
SfPropertyBase(string name)
{
Name = name;
}
virtual ~SfPropertyBase() {}
string Name;
virtual bool FromString(Object* obj, string str) = 0;
};
template< typename T>
class Property : public SfPropertyBase
{
public:
Property(string name) : SfPropertyBase(name)
{
//specific to Property stuff
}
template<typename U = T>
typename std::enable_if<(std::is_class<U>::value && std::is_pointer<U>::value), bool>::type
FromString(Object* obj, string str)
{
//do something
return true;
}
template<typename U = T>
typename std::enable_if<!std::is_class<U>::value || !std::is_pointer<U>::value), bool>::type
FromString(Object* obj, string str)
{
//do something
return true;
}
}
Then, when I try to initialize an instance of this class:
auto prop = new Property<int>("IntProperty");
I get invalid new-expression of abstract class type Property<int>. I understand that there is an abstract function in PropertyBase, but I also provide both specializations for Property, where T is a class and where it isn't.
What is going on and how to fix it?
Note: what I want to achieve is to specialize FromString if T is a class/pointer and all the other cases.
Both the FromString in Property are function template, they can't override the non-template virtual function of the base class. (In fact functions templates cannot be virtual functions).
You could add another non-template FromString in Property; and you can ensure the overriding by using the keyword orverride. e.g.
bool FromString(Object* obj, string str) override {
return FromString<>(obj, str);
}
LIVE
A function template cannot be used as an overrider for a non-template virtual function. A function template is not a function, it's a recipe for creating functions on demand when a call is made.
Code will have to call FromString on your derived class object directly for SFINAE to work. If you want to provide a different overrider based on the template parameter type, one approach is to go via an intermediate base.
template<typename T, typename = void>
struct FromStringProvider;
template<typename T>
struct FromStringProvider<T, typename std::enable_if<(std::is_class<U>::value && std::is_pointer<U>::value)>::type> : SfPropertyBase {
bool FromString(Object* obj, string str) override
{
//do something
return true;
}
};
If you need access to the deriving class, then a CRTP based approach can be used. Just pass the deriving class as an extra parameter and rely on its static interface to access the parts you need.
This alternative approach is especially useful if you have sets of virtual functions, all under the same conditions.
I have an issue I'm facing where I'm trying to build a factory function that,
given an ID and a type will return the correct (templated) subclass.
What this is trying to solve:
The id() values are sent across a network as soon as a connection is established, and specify to the receiver how a sequence of bytes are encoded. The receiver knows in advance the type T that it expects, but does not know how that type T is encoded on the wire until it gets this value. It also specifies how return values (of some type U, where U may or may not be the same type as T) should be marshalled when they are returned. This code is used generally, i.e. there are multiple senders/receivers that use/expect different types; the types used between a given sender/receiver pair are always fixed, however.
A basic sketch of the problem: we have a (simplified) base class that defines id()
template <typename T>
class foo
{
public:
virtual ~foo() { }
// Other methods
// This must return the same value for every type T
virtual std::uint8_t id() const noexcept = 0;
};
From there, we have some subclasses:
template <typename T>
class bar : public foo<T>
{
public:
std::uint8_t id() const noexcept override { return 1; }
};
template <typename T>
class quux : public foo<T>
{
public:
std::uint8_t id() const noexcept override { return 2; }
};
For the actual factory function, I need to store something that
erases the type (e.g. bar, quux) so that I can store the actual
creation function in a homogenous container.
Effectively, I want semantics that are roughly equivalent to:
struct creation_holder
{
// Obviously this cannot work, as we cannot have virtual template functions
template <typename T>
virtual foo<T>* build() const;
};
template <template <typename> class F>
struct create : public creation_holder
{
// As above
template <typename T>
foo<T>* build() const override
{
return new F<T>();
}
};
std::unordered_map<std::uint8_t, create*>& mapping()
{
static std::unordered_map<std::uint8_t, create*> m;
return m;
}
template <typename T, template <typename> class F>
bool register_foo(F<T> foo_subclass,
typename std::enable_if<std::is_base_of<foo<T>, F<T>>::value>::type* = 0)
{
auto& m = mapping();
const auto id = foo_subclass.id();
creation_holder* hold = new create<F>();
// insert into map if it's not already present
}
template <typename T>
foo<T>* from_id(std::uint8_t id)
{
const auto& m = mapping();
auto it = m.find(id);
if(it == m.end()) { return nullptr; }
auto c = it->second;
return c->build<T>();
}
I've played around with a number of ideas to try and get something with similar
semantics, but with no luck. Is there a way to do this (I don't care if the
implementation is significantly different).
Some utility types for passing around types and bundles of types:
template<class...Ts>
struct types_t {};
template<class...Ts>
constexpr types_t<Ts...> types{}; // C++14. In C++11, replace types<T> with types_t<T>{}. Then again, I don't use it.
template<class T>
struct tag_t {};
template<class T>
constexpr tag_t<T> tag{}; // C++14. In C++11, replace tag<T> with tag_t<T>{} below
Now we write a poly ifactory.
Here is an ifactory:
template<template<class...>class Z, class T>
struct ifactory {
virtual std::unique_ptr<Z<T>> tagged_build(tag_t<T>) const = 0;
virtual ~ifactory() {}
};
you pass in the tag you want to build and you get out an object. Pretty simple.
We then bundle them up (this would be easier in c++171, but you asked for c++11):
template<template<class...>class Z, class Types>
struct poly_ifactory_impl;
The one type case:
template<template<class...>class Z, class T>
struct poly_ifactory_impl<Z,types_t<T>>:
ifactory<Z, T>
{
using ifactory<Z, T>::tagged_build;
};
the 2+ case:
template<template<class...>class Z, class T0, class T1, class...Ts>
struct poly_ifactory_impl<Z,types_t<T0, T1, Ts...>>:
ifactory<Z, T0>,
poly_ifactory_impl<Z, types_t<T1, Ts...>>
{
using ifactory<Z, T0>::tagged_build;
using poly_ifactory_impl<Z, types_t<T1, Ts...>>::tagged_build;
};
We import the tagged_build method down into the derived classes. This means that the most-derived poly_ifactory_impl has all of the tagged_build methods in the same overload set. We'll use this to dispatch to them.
Then we wrap it up pretty:
template<template<class...>class Z, class Types>
struct poly_ifactory:
poly_ifactory_impl<Z, Types>
{
template<class T>
std::unique_ptr<Z<T>> build() const {
return this->tagged_build(tag<T>);
}
};
notice I'm returning a unique_ptr; returing a raw T* from a factory method is code smell.
Someone with a poly_ifactory<?> just does a ->build<T>() and ignores the tagged_ overloads (unless they want them; I leave them exposed). Each tagged_build is virtual, but build<T> is not. This is how we emulate a virtual template function.
This handles the interface. At the other end we don't want to have to implement each build(tag_t<T>) manually. We can solve this with the CRTP.
template<class D, class Base, template<class...>class Z, class T>
struct factory_impl : Base {
virtual std::unique_ptr<Z<T>> tagged_build( tag_t<T> ) const override final {
return static_cast<D const*>(this)->build_impl( tag<T> );
}
using Base::build;
};
template<class D, class Base, template<class...>class Z, class Types>
struct poly_factory_impl;
the 1 type case:
template<class D, class Base, template<class...>class Z, class T0>
struct poly_factory_impl<D, Base, Z, types_t<T0>> :
factory_impl<D, Base, Z, T0>
{
using factory_impl<D, Base, Z, T0>::tagged_build;
};
the 2+ type case:
template<class D, class Base, template<class...>class Z, class T0, class T1, class...Ts>
struct poly_factory_impl<D, Base, Z, types_t<T0, T1, Ts...>> :
factory_impl<D, poly_factory_impl<D, Base, Z, types_t<T1, Ts...>>, Z, T0>
{
using factory_impl<D, poly_factory_impl<D, Base, Z, types_t<T1, Ts...>>, Z, T0>::tagged_build;
};
what this does is write a series of tagged_build(tag_t<T>) overloads of the ifactory methods, and redirects them to D::build_impl(tag_t<T>), where D is a theoretical derived type.
The fancy "pass Base around" exists to avoid having to use virtual inheritance. We inherit linearly, each step implementing one tagged_build(tag<T>) overload. All of them dispatch downward non-virtually using CRTP.
Use looks like:
struct bar {};
using my_types = types_t<int, double, bar>;
template<class T>
using vec = std::vector<T>;
using my_ifactory = poly_ifactory< vec, my_types >;
struct my_factory :
poly_factory_impl< my_factory, my_ifactory, vec, my_types >
{
template<class T>
std::unique_ptr< vec<T> > build_impl( tag_t<T> ) const {
return std::make_unique< std::vector<T> >( sizeof(T) );
// above is C++14; in C++11, use:
// return std::unique_ptr<vec<T>>( new vec<T>(sizeof(T)) );
}
};
and an instance of my_factory satisfies the my_ifactory interface.
In this case, we create a unique ptr to a vector of T with a number of elements equal to sizeof(T). It is just a toy.
Live example.
The pseudo code design.
The interface has a
template<class T> R build
function. It dispatches to
virtual R tagged_build(tag_t<T>) = 0;
methods.
The Ts in question are extracted from a types_t<Ts...> list. Only those types are supported.
On the implementation side, we create a linear inheritance of CRTP helpers. Each inherits from the last, and overrides a virtual R tagged_build(tag_t<T>).
The implementation of tagged_build uses CRTP to cast the this pointer to a more-derived class and call build_impl(tag<T>) on it. This is an example of non-runtime polymorphism.
So calls go build<T> to virtual tagged_build(tag_t<T>) to build_impl(tag<T>). Users just interact with one template; implementors just implement one template. The glue in the middle -- the virtual tagged_build -- is generated from a types_t list of types.
This is about 100 lines of "glue" or helper code, and in exchange we get effectively virtual template methods.
1 in c++17 this becomes:
template<template<class...>class Z, class...Ts>
struct poly_ifactory_impl<Z,types_t<Ts...>>:
ifactory<Z, Ts>...
{
using ifactory<Z, Ts>::tagged_build...;
};
which is much simpler and clearer.
Finally, you can do something vaguely like this without a central list of types. If you know both the caller and the callee know the type you could pass a typeid or typeindex into the ifactory, pass a void* or something similar out over the virtual dispatch mechanism, and cast/check for null/do a lookup in a map to types.
The internal implementation would look similar to this one, but you wouldn't have to publish types_t as part of your formal (or binary) interface.
Externally, you would have to "just know" what types are supported. At runtime, you might get a null smart (or dumb, ick) pointer out if you pass in an unsupported type.
With a bit of care you could even do both. Expose an efficient, safe mechanism to get compile-time known types applied to a template. Also expose a "try" based interface that both uses the efficient compile-time known system (if the type matches) and falls back on the inefficient runtime checked on. You might do this for esoteric backwards binary compatibility reasons (so new software can connect over an obsolete interface to new or old API implementations and handle having an old API implementation dynamically).
But at that point, have you considered using COM?
I want to have a function template inside a regular (non-template) class, which allocates a derived class with the needed parameters and returns a pointer to the base class:
class Factory {
public:
BaseClass_T * createObject(parameters) { return new Derived_T(parameters); }
};
So far I've only been using templates where parameters vary in type, but are always the same count. Since my different derived classes have different constructor signatures, I wonder if there is a way to template that and specify the generated function's parameter type and count via a template, something like this:
Factory f;
f.createObject<Derived1, void>(); // create createObject() for Derivev1() constructor
f.createObject<Derived2, int, double>(); // create createObject() for Derived2(int, double) constructor
You can use a variadic template:
#include <utility>
struct BaseClass_T { ~virtual BaseClass_T() = default; };
struct Factory
{
template <typename Der, typename ...Args>
BaseClass_T * create(Args &&... args)
{
return new Der(std::forward<Args>(args)...);
}
};
An even better design would be for your factory to return std::unique_ptr<BaseClass_T>:
#include <memory>
struct SaneFactory
{
template <typename Der, typename ...Args>
std::unique_ptr<BaseClass_T> create(Args &&... args)
{
return std::make_unique<Der>(std::forward<Args>(args)...);
}
};
I'm pretty new to both C++ and templates, and I'm trying to adapt a helper class that can be used to make delegates from member functions.
I changed this code (which compiles):
Delegate<void, int, int>* cheaty(void (Renderer::*method)(int, int), Renderer* obj)
{
auto maker = DelegateMaker<Renderer, void, int, int>();
return maker.BindPointer<&Renderer::MoveCamera>(obj);
}
To this:
Delegate<void, int, int>* cheaty(void (Renderer::*method)(int, int), Renderer* obj)
{
auto maker = DelegateMaker<Renderer, void, int, int>();
return maker.BindPointer<method>(obj);
}
Which doesn't compile and gives the following error: error: 'method' is not a valid template argument for type 'void (Engine::Renderer::*)(int, int)'. Is what I am trying to achieve simply impossible because of limitations in C++ templates? Or am I just missing something really obvious?
Edit:
Ideally, what I'd like to have is a function like this:
template<typename T, typename return_type, typename... params>
Delegate<return_type, params...>* make_delegate_pointer(return_type (T::*name)(params...), T* obj)
{
DelegateMaker<T, return_type, params...> maker = DelegateMaker<T, return_type, params...>();
return maker.BindPointer<name>(obj);
}
And then call it like this auto delegate = Delegates::make_delegate_pointer(&Class::Method, &classInstance); Only, the problem I keep running into is the fact that there seems to be some difference between calling BindPointer like this maker.BindPointer<&Class::Method>(classInstance); and calling it like this maker.BindPointer<return_type (Class::*)(arguments...)>(classInstance);.
However, return_type (T::*)(params...) memberFuncPointer = &Class::Method compiles fine. Which means that logically, maker.BindPointer<return_type (T::*)(params...)>(classInstance) should compile as well (or some variation on that, which is why in the orginal question I attempted to use method as void (Renderer::*method)(int, int)). But it doesn't.
Template parameter values must be known at compile-time, but your method value is not known until runtime since cheaty() does not know which method of Renderer is being passed to it. Thus the compiler error. You will have to change BindPointer to not use a template anymore. Besides, DelegateMaker already knows the method signature, so you do not need to duplicate that information as template parameters in BindPointer(), let it inherit the values from DelegateMaker.
For example (untested, might need some tweaking, but you should get the general idea):
template <typename ReturnType, typename... ParamTypes>
class Delegate
{
public:
virtual ReturnType Invoke(ParamTypes... params) = 0;
};
template <typename ClassType, typename ReturnType, typename... ParamTypes>
class DelegateMaker
{
public:
typedef ReturnType (ClassType::*MethodType)(ParamTypes... params);
private:
class DelegateImpl : public Delegate<ReturnType, ParamTypes...>
{
private:
ClassType* _obj;
MethodType _method;
public:
DelegateImpl(ClassType *obj, MethodType method)
: _obj(obj), _method(method)
{
}
virtual ReturnType Invoke(ParamTypes... params)
{
return (_obj.*_method)(params);
}
};
public:
Delegate<ReturnType, ParamTypes...>* BindPointer(MethodType method, ClassType *obj)
{
return new DelegateImpl(obj, method);
}
};
template <typename ClassType, typename ReturnType, typename... ParamTypes>
Delegate<ReturnType, ParamTypes...>* make_delegate_pointer(
DelegateMaker<ClassType, ReturnType, ParamTypes...>::MethodType method,
ClassType* obj)
{
DelegateMaker<ClassType, ReturnType, ParamTypes...> maker;
return maker.BindPointer(method, obj);
}
auto delegate = Delegates::make_delegate_pointer(&Class::Method, &classInstance);