How to support multiple construction signatures in a factory design? - c++

I'm working with the following (simplified) factory design to create objects of some inheritance hierarchy, shouldn't be anything special:
// class to create
class Class
{
public:
Class(Type type, Foo foo);
};
// Simple creator class.
// Used in practice to do some runtime checks about whether or not construction is allowed.
class Creator
{
public:
Class* create( Type type, Foo foo ) const
{
return new Class( type, foo );
}
};
class Factory
{
public:
Factory
{
// fill object creator map on construction
_map[ "name" ] = new Creator<Class>;
}
Class* create( const std::string& name, Type type, Foo foo )
{
// fowards to map entry
return _map[name]->create( type, foo );
}
private:
std::map<std::string, Creator*> _map;
}
// client code
int main()
{
Factory f;
factory.create(name, type, foo);
}
Now I run into problems once I want to create subclasses which have a different constructor signature because the factory imposes a fixed signature on the entire inheritance hierarchy. I.e. for the following class I have no way of specifying the new 3rd parameter via the factory construction without imposing this extended signature on all other class of my hierarchy again.
class ExtClass : public Class
{
public:
Class(Type type, Foo foo, NewMember nm)
: Class(type, foo),
_nm(nm)
private:
NewMember _nm;
};
Is there a way to make this work with my current design without making pricinpal changes? I'm thinking of using templates or bind objects to make varying argument calls possible.
Or would you in this case suggest a different solution than the factory design?

This answer is different enough to my first solution and it includes what you might consider "principal changes" that I have made it a separate answer:
In my opinion, it is superior to my earlier solution, but it depends what your exact requirements are. The features here are:
Creator id is unique.
CreateObject supports implicit conversion of parameters.
The same limitation that the constructors must take const& parameters exists. It might not matter, but this solution only requires C++11. It would, of course, be a bit simpler with the new C++17 tuple features.
#include <boost/functional/factory.hpp>
#include <boost/function.hpp>
#include <boost/variant.hpp>
#include <map>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
// Just for debugging.
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
// Tuple manipulation.
template <typename Signature>
struct signature_impl;
template <typename ReturnType, typename... Args>
struct signature_impl<ReturnType(Args...)>
{
using return_type = ReturnType;
using param_types = std::tuple<Args...>;
};
template <typename T>
using signature_t = signature_impl<T>;
template <std::size_t... Ints>
struct indices {};
template <std::size_t N, std::size_t... Ints>
struct build_indices : build_indices<N-1, N-1, Ints...> {};
template <std::size_t... Ints>
struct build_indices<0, Ints...> : indices<Ints...> {};
template <typename Tuple>
using make_tuple_indices = build_indices<std::tuple_size<typename std::remove_reference<Tuple>::type>::value>;
// The multiple-signature factory.
template <class AbstractProduct, typename IdentifierType, typename... ProductCreators>
class multifactory
{
using functions = boost::variant<boost::function<ProductCreators>...>;
std::map<IdentifierType, functions> associations_;
template <typename Signature>
struct dispatch_foo
{
template <typename CreateArgs, std::size_t... Indices>
typename std::enable_if<std::is_convertible<CreateArgs, typename signature_t<Signature>::param_types>::value, AbstractProduct>::type
static apply(boost::function<Signature> const &f, CreateArgs && t, indices<Indices...>)
{
return f(std::get<Indices>(std::forward<CreateArgs>(t))...);
}
template <typename CreateArgs, std::size_t... Indices>
typename std::enable_if<!std::is_convertible<CreateArgs, typename signature_t<Signature>::param_types>::value, AbstractProduct>::type
static apply(boost::function<Signature> const &, CreateArgs &&, indices<Indices...>)
{
return nullptr;
}
};
template <typename... CreateArguments>
struct dispatcher : boost::static_visitor<AbstractProduct>
{
std::tuple<CreateArguments...> args;
dispatcher(CreateArguments const&... args) : args{std::forward_as_tuple(args...)} {}
template <typename Signature>
AbstractProduct operator()(boost::function<Signature> const &f) const
{
int status;
std::cout << "visitor: " << abi::__cxa_demangle(typeid(Signature).name(), nullptr, 0, &status) << "\n";
return dispatch_foo<Signature>::apply(f, args, make_tuple_indices<std::tuple<CreateArguments...>>{});
}
};
public:
template <typename ProductCreator>
bool Register(IdentifierType id, ProductCreator &&creator) {
return associations_.emplace(id, std::forward<ProductCreator>(creator)).second;
}
bool Unregister(const IdentifierType& id) {
return associations_.erase(id) == 1;
}
template <typename... Arguments>
AbstractProduct CreateObject(const IdentifierType& id, Arguments const& ... args) {
auto i = associations_.find(id);
if (i != associations_.end()) {
dispatcher<Arguments...> impl(args...);
return boost::apply_visitor(impl, i->second);
}
throw std::runtime_error("Creator not found.");
}
};
struct Arity {
virtual ~Arity() = default;
};
struct Nullary : Arity {};
struct Unary : Arity {
Unary() {} // Also has nullary ctor.
Unary(int) {}
};
int main(void)
{
multifactory<Arity*, int, Arity*(), Arity*(const int&)> factory;
factory.Register(0, boost::function<Arity*()>( boost::factory<Nullary*>() ));
factory.Register(1, boost::function<Arity*(const int&)>(boost::factory<Unary*>()) );
auto a = factory.CreateObject(0);
assert(a);
assert(typeid(*a) == typeid(Nullary));
auto b = factory.CreateObject(1, 2);
assert(b);
assert(typeid(*b) == typeid(Unary));
}

Apologies for the different naming conventions, but this is the C++14 solution that I currently use. The two main shortcomings are
when calling CreateObject, the type of the value passed as an
argument must be the same as the type registered. You can't pass in
a float and call a constructor registered with a double
signature.
Due to an implementation detail in boost::bind,
parameters must be const &.
A design limitation because I wanted to use boost::factory is that objects of that class must be wrapped in a boost::function (to disambiguate the function signature).
So it works but it could definitely be improved with more metaprogramming wisdom:
#include <boost/functional/factory.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <cassert>
#include <map>
#include <tuple>
#include <type_traits>
#include <utility>
template <class AbstractProduct, typename IdentifierType, typename... ProductCreators>
class Factory
{
using AssociativeContainers = std::tuple<std::map<IdentifierType, boost::function<ProductCreators>>...>;
public:
template <typename Product, typename... Arguments>
bool Register(const IdentifierType& id, boost::function<Product(Arguments...)> creator) {
auto &foo = std::get<std::map<IdentifierType, boost::function<AbstractProduct(const Arguments&...)>>>(associations_);
return foo.emplace(id, creator).second;
}
// This function left as an exercise to the reader...
bool Unregister(const IdentifierType& id) {
return associations_.erase(id) == 1;
}
template <typename... Arguments>
AbstractProduct CreateObject(const IdentifierType& id, Arguments&& ... args) const {
auto const &foo = std::get<std::map<IdentifierType, boost::function<AbstractProduct(const Arguments&...)>>>(associations_);
auto const i = foo.find(id);
if (i != foo.end()) {
return (i->second)(std::forward<Arguments...>(args)...);
}
throw std::runtime_error("Creator not found.");
}
private:
AssociativeContainers associations_;
};
struct Arity {
virtual ~Arity() = default;
};
struct Nullary : Arity {};
struct Unary : Arity {
Unary() {}
Unary(double x) : x(x) {}
double x;
};
int main(void)
{
Factory<Arity*, int, Arity*(), Arity*(const double&)> factory;
factory.Register(0, boost::function<Arity*()>{boost::factory<Nullary*>()} );
factory.Register(1, boost::function<Arity*(const double&)>{boost::bind(boost::factory<Unary*>(), _1)});
auto x = factory.CreateObject(1, 2.0);
assert(typeid(*x) == typeid(Unary));
x = factory.CreateObject(0);
assert(typeid(*x) == typeid(Nullary));
}

Related

C++ lambda as parameter with variable arguments

I want to create an event system that uses lambda functions as its subscribers/listeners, and an event type to assign them to the specific event that they should subscribe to. The lambdas should have variable arguments, as different kinds of events use different kinds of arguments/provide the subscribers with different kinds of data.
For my dispatcher, I have the following:
class EventDispatcher {
public:
static void subscribe(EventType event_type, std::function<void(...)> callback);
void queue_event(Event event);
void dispatch_queue();
private:
std::queue<Event*> event_queue;
std::map<EventType, std::function<void(...)>> event_subscribers;
};
No issues here, but when I go to implement the subscribe() function in my .cpp file, like this:
void EventDispatcher::subscribe(EventType event_type, std::function<void(...)> callback) {
... (nothing here yet)
}
The IDE shows me this:
Implicit instantiation of undefined template 'std::function<void (...)>'
Don't try to plop event callbacks with different parameter types directly into a single map.
Instead, create a template to store the callback (templated by the parameter types), and store pointers to its non-template base.
Here's how I would do it:
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <queue>
#include <tuple>
#include <typeindex>
#include <typeinfo>
#include <type_traits>
#include <utility>
struct Event
{
virtual ~Event() = default;
};
struct Observer
{
virtual ~Observer() = default;
virtual void Observe(const Event &e) const = 0;
};
template <typename ...P>
struct BasicEvent : Event
{
std::tuple<P...> params;
BasicEvent(P ...params) : params(std::move(params)...) {}
struct EventObserver : Observer
{
std::function<void(P...)> func;
template <typename T>
EventObserver(T &&func) : func(std::forward<T>(func)) {}
void Observe(const Event &e) const override
{
std::apply(func, dynamic_cast<const BasicEvent &>(e).params);
}
};
// We need a protected destructor, but adding one silently removes the move operations.
// And adding the move operations removes the copy operations, so we add those too.
BasicEvent(const BasicEvent &) = default;
BasicEvent(BasicEvent &&) = default;
BasicEvent &operator=(const BasicEvent &) = default;
BasicEvent &operator=(BasicEvent &&) = default;
protected:
~BasicEvent() {}
};
class EventDispatcher
{
public:
template <typename E>
void Subscribe(typename E::EventObserver observer)
{
event_subscribers.insert_or_assign(typeid(E), std::make_unique<typename E::EventObserver>(std::move(observer)));
}
template <typename E>
void QueueEvent(E &&event)
{
event_queue.push(std::make_unique<std::remove_cvref_t<E>>(std::forward<E>(event)));
}
void DispatchQueue()
{
while (!event_queue.empty())
{
Event &event = *event_queue.front();
event_subscribers.at(typeid(event))->Observe(event);
event_queue.pop();
}
}
private:
std::queue<std::unique_ptr<Event>> event_queue;
std::map<std::type_index, std::unique_ptr<Observer>> event_subscribers;
};
struct EventA : BasicEvent<> {using BasicEvent::BasicEvent;};
struct EventB : BasicEvent<> {using BasicEvent::BasicEvent;};
struct EventC : BasicEvent<int, int> {using BasicEvent::BasicEvent;};
int main()
{
EventDispatcher dis;
dis.Subscribe<EventA>([]{std::cout << "Observing A!\n";});
dis.Subscribe<EventB>([]{std::cout << "Observing B!\n";});
dis.Subscribe<EventC>([](int x, int y){std::cout << "Observing C: " << x << ", " << y << "!\n";});
dis.QueueEvent(EventA());
dis.QueueEvent(EventB());
dis.QueueEvent(EventC(1, 2));
dis.DispatchQueue();
}
You could create your own version of std::function that accepts functions of any signature using type erasure. This will require some heavy lifting though. I will provide a solution for void functions which requires C++17, because we will use std::any.
I will walk you through the steps first and then provide a full solution in code.
First you create some function_traits that capture the number and type of arguments of any kind of function using template meta-programming. We can "borrow" from here.
Then you create a class VariadicVoidFunction that has a templated call operator.
This call operator creates a std::vector<std::any> and passes it to the invoke method of a member of VariadicVoidFunction, which is a (resource-owning smart) pointer of type VariadicVoidFunction::Concept.
VariadicVoidFunction::Concept is an abstract base class with a virtual invoke method that accepts std::vector<std::any>.
VariadicVoidFunction::Function is a class template, where the template parameter is a function. It stores this function as member and inherits VariadicVoidFunction::Concept. It implements the invoke method. Here, we can std::any_cast the vector elements back to the expected types, which we can extract using function_traits. This allows us to call the actual function with the correct argument types.
VariadicVoidFunction gets a templated constructor accepting any kind of function F. It creates an instance of type VariadicVoidFunction::Function<F> and stores it in an owning (smart) pointer.
#include <memory>
#include <vector>
#include <any>
// function_traits and specializations are needed to get arity of any function type
template<class F>
struct function_traits;
// ... function pointer
template<class R, class... Args>
struct function_traits<R(*)(Args...)> : public function_traits<R(Args...)>
{};
// ... normal function
template<class R, class... Args>
struct function_traits<R(Args...)>
{
static constexpr std::size_t arity = sizeof...(Args);
template <std::size_t N>
struct argument
{
static_assert(N < arity, "error: invalid parameter index.");
using type = typename std::tuple_element<N,std::tuple<Args...>>::type;
};
};
// ... non-const member function
template<class C, class R, class... Args>
struct function_traits<R(C::*)(Args...)> : public function_traits<R(C&,Args...)>
{};
// ... const member function
template<class C, class R, class... Args>
struct function_traits<R(C::*)(Args...) const> : public function_traits<R(C const&,Args...)>
{};
// ... functor (no overloads allowed)
template<class F>
struct function_traits
{
private:
using call_type = function_traits<decltype(&F::operator())>;
public:
static constexpr std::size_t arity = call_type::arity - 1;
template <std::size_t N>
struct argument
{
static_assert(N < arity, "error: invalid parameter index.");
using type = typename call_type::template argument<N+1>::type;
};
};
template<class F>
struct function_traits<F&> : public function_traits<F>
{};
template<class F>
struct function_traits<F&&> : public function_traits<F>
{};
// type erased void function taking any number of arguments
class VariadicVoidFunction
{
public:
template <typename F>
VariadicVoidFunction(F const& f)
: type_erased_function{std::make_shared<Function<F>>(f)} {}
template <typename... Args>
void operator()(Args&&... args){
return type_erased_function->invoke(std::vector<std::any>({args...}));
}
private:
struct Concept {
virtual ~Concept(){}
virtual void invoke(std::vector<std::any> const& args) = 0;
};
template <typename F>
class Function : public Concept
{
public:
Function(F const& f) : func{f} {}
void invoke(std::vector<std::any> const& args) override final
{
return invoke_impl(
args,
std::make_index_sequence<function_traits<F>::arity>()
);
}
private:
template <size_t... I>
void invoke_impl(std::vector<std::any> const& args, std::index_sequence<I...>)
{
return func(std::any_cast<typename function_traits<F>::template argument<I>::type>(args[I])...);
}
F func;
};
std::shared_ptr<Concept> type_erased_function;
};
You can use it like this:
#include <unordered_map>
#include <iostream>
int main()
{
VariadicVoidFunction([](){});
std::unordered_map<size_t, VariadicVoidFunction> map =
{
{0, VariadicVoidFunction{[](){ std::cout << "no argument\n"; }} },
{1, VariadicVoidFunction{[](int i){ std::cout << "one argument\n"; }} },
{2, VariadicVoidFunction{[](double j, const char* x){ std::cout<< "two arguments\n"; }} }
};
map.at(0)();
map.at(1)(42);
map.at(2)(1.23, "Hello World");
return 0;
}
no argument
one argument
two arguments
Demo on Godbolt Compiler explorer
Note that this is a prototypical solution to get you started. One downside is that all arguments will be copied into the std::any You could avoid this by passing pointers to std::any, but you have to be careful with lifetimes when you do this.
After the input from #joergbrech and #HolyBlackCat I made this
enum class EventType {
WindowClosed, WindowResized, WindowFocused, WindowLostFocus, WindowMoved,
AppTick, AppUpdate, AppRender,
KeyPressed, KeyRelease,
MouseButtonPressed, MouseButtonRelease, MouseMoved, MouseScrolled,
ControllerAxisChange, ControllerButtonPressed, ControllerConnected, ControllerDisconnected
};
class IEvent {
public:
IEvent(EventType event_type) {
this->event_type = event_type;
}
EventType get_event_type() {
return event_type;
}
private:
EventType event_type;
};
class IEventSubscriber {
public:
/**
* #param event The event that is passed to the subscriber by the publisher; should be cast to specific event
* */
virtual void on_event(IEvent *event) = 0;
EventType get_event_type() {
return event_type;
}
protected:
explicit IEventSubscriber(EventType event_type) {
this->event_type = event_type;
}
private:
EventType event_type;
};
class FORGE_API EventPublisher {
public:
static void subscribe(IEventSubscriber *subscriber);
static void queue_event(IEvent *event);
static void dispatch_queue();
private:
static std::queue<IEvent*> event_queue;
static std::set<IEventSubscriber*> event_subscribers;
};
I've tested it and I get the expected result from this solution. For the full code solution -> https://github.com/F4LS3/forge-engine
std::function has no specialization for variadic function types.
You likely want std::function<void()>.

C++ O(1) lookup by derived type

I have a vector of pointers to Base.
Invariant: only one of each derived type should be in that vector at any time.
I also want to be able to lookup the value with a given type in O(1). I can do this in O(n) easily, by checking dynamic_cast.
Basically, I want to replace my vector with a map or something. Is that possible?
Here's minimal example with the vector and the loop:
#include <functional>
#include <iostream>
#include <memory>
#include <type_traits>
#include <vector>
using namespace std;
typedef struct Base {
virtual ~Base(){};
} Base;
vector<unique_ptr<Base>> baseList;
template <typename NarrowType,
typename std::enable_if_t<
! std::is_same_v<Base, NarrowType> &&
std::is_base_of_v<Base, NarrowType>,
bool> = true>
void ApplyFuncToType(function<void(NarrowType)> func) {
// Want to get rid of this loop
for (auto &base : baseList) {
NarrowType *narrow = dynamic_cast<NarrowType *>(base.get());
if (narrow) {
func(*narrow);
}
}
}
// usage
int main() {
typedef struct A : Base {
void printA() { cout << "a" << endl; }
} A;
typedef struct B : Base {
void printB() { cout << "b" << endl; }
} B;
baseList.push_back(make_unique<A>());
baseList.push_back(make_unique<B>());
ApplyFuncToType<A>([](A a) { a.printA(); });
}
Questions:
How can I enfore my invariant (one of each type max in container)
Would a unordered_map<type_info, unique_ptr<Base>> be a good solution to this? I have read that typeid is not consistent or safe to use or something, but am not sure exactly.
Edits/Clarification:
This is for a system where other classes can register their own types in this vector. i.e. the contents of the vector will change during runtime.
A similar approach is shown here, where an unordered_map is used to allow self-registered event callbacks.
Yeah, sure, it's possible, but I'm not convinced you need it. After all, all your types are completely static.
Also, ApplyFuncToType shouldn't be taking std::function, but a generic argument, since you'll save on the cost of shoehorning things into std::function. You're not deducing any types anyway - because std::function is not a tool for that - and thus you have the call that includes the type parameter explicitly: ApplyFuncToType<A>.
And finally, it's probably wrong to pass A and B to the lambda by value - since then the instance the lambda is using is not the instance you so carefully deposited beforehand (!). It should be passed by const reference, or by reference if it's a non-const method:
// Do this
ApplyFuncToType<A>([](const A &a) { a.printA(); });
// Or do that
ApplyFuncToType<A>([](A &a) { a.printA(); });
// NO!
ApplyFuncToType<A>([](A a) { a.printA(); });
It's hard to deduce it ahead of time, but I imagine that you'd want to make A, B, ... non-copyable but they definitely should be movable (read on).
A Tuple of Pointers
All you really want is the below - and it doesn't care that the types are derived from some base, you can use any types you wish. You can of course add type constraints if you want to protect from bugs where wrong types are supplied to ptr_tuple.
#include <functional>
#include <memory>
#include <tuple>
struct A { void methodA() {} };
struct B { void methodB() {} };
template <class ...Args>
using ptr_tuple = std::tuple<std::unique_ptr<Args>...>;
ptr_tuple<A, B> instances;
template <typename T>
auto &instance()
{
return std::get<std::unique_ptr<T>>(instances);
}
template <class T, class Fun, class ...Args>
void invoke(Fun &&fun, Args &&...args)
{
auto *ptr = instance<T>().get();
if (ptr) {
std::invoke(fun, *ptr, std::forward<Args>(args)...);
}
}
int main() {
instance<A>() = std::make_unique<A>();
instance<B>() = std::make_unique<B>();
invoke<A>([](A& a){ a.methodA(); });
invoke<B>([](B& b){ b.methodB(); });
}
Argument Deduction for Invoke/Apply
It's not even necessary to supply the explicit type parameter to invoke. We can deduce it. For that, we use a traits class that's sorely missing in C++ standard library:
// from https://stackoverflow.com/a/39717241/1329652
// see also
// https://github.com/kennytm/utils/blob/master/traits.hpp
// https://stackoverflow.com/a/27885283/1329652
// boost::callable_traits
template <typename T, typename = void>
struct function_traits;
template <typename R, typename... A>
struct function_traits<R (*)(A...)>
{
using args_type = std::tuple<A... >;
using arg0_class = std::decay_t<std::tuple_element_t<0, args_type>>;
};
template <typename R, typename C, typename... A>
struct function_traits<R (C::*)(A...)>
{
using args_type = std::tuple<A... >;
using arg0_class = std::decay_t<std::tuple_element_t<0, args_type>>;
};
template <typename R, typename C, typename... A>
struct function_traits<R (C::*)(A...) const>
{
using args_type = std::tuple<A... >;
using arg0_class = std::decay_t<std::tuple_element_t<0, args_type>>;
};
template <typename T>
struct function_traits<T, std::void_t<decltype(&T::operator())> >
: public function_traits< decltype(&T::operator()) >
{};
And then we can deduce the needed type in invoke:
template <class Fun, class ...Args>
void invoke(Fun &&fun, Args &&...args)
{
using arg0_class = typename function_traits<std::decay_t<Fun>>::arg0_class;
auto *ptr = instance<arg0_class>().get();
if (ptr) {
std::invoke(fun, *ptr, std::forward<Args>(args)...);
}
}
int main() {
instance<A>() = std::make_unique<A>();
instance<B>() = std::make_unique<B>();
invoke([](A& a){ a.methodA(); });
invoke([](B& b){ b.methodB(); });
}
A Tuple of Optional Values
Depending on what your A and B types really are, if they can be moved, then using dynamic memory allocation is totally unnecessary, you'd much rather keep them by value, e.g. with optional:
#include <functional>
#include <memory>
#include <optional>
#include <tuple>
struct A { void methodA() {} };
struct B { void methodB() {} };
template <class ...Args>
using opt_tuple = std::tuple<std::optional<Args>...>;
opt_tuple<A, B> instances;
template <typename T> auto &instance()
{
return std::get<std::optional<T>>(instances);
}
template <class T, class Fun, class ...Args>
void invoke(Fun &&fun, Args &&...args)
{
auto &opt = instance<T>();
if (opt) {
std::invoke(fun, *opt, std::forward<Args>(args)...);
}
}
int main() {
instance<A>().emplace(); // constructs A
instance<B>().emplace(); // constructs B
invoke<A>([](A& a){ a.methodA(); });
invoke<B>([](B& b){ b.methodB(); });
}
Of course you can add the type-deduced variant of invoke just as before.
A type-id Stand In
Even though I really think that your original solution is in want of a problem - you should state what problem you're trying to solve, otherwise it smells of an XY problem - there of course is a better "type id" than type_id: an address of a function templated on a type. There'll be only one instance of it per program.
I don't think that the "O(1)" lookup is a real requirement, a very, very fast O(log(N)) lookup - way faster than you'd get from e.g. std::map, will work just as well for whatever your imaginary applications is.
Thus:
#include <cassert>
#include <functional>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <vector>
// here goes function_traits implementation from above
struct Base {};
template <typename T>
constexpr static bool is_derived_from_Base_v =
!std::is_same_v<Base, T> && std::is_base_of_v<Base, T>;
class UniqueTypeObjects {
using marker_type = void(*)();
struct Pair {
std::unique_ptr<Base> base;
marker_type marker;
Pair(std::unique_ptr<Base> &&base, marker_type marker) : base(std::move(base)), marker(marker) {}
bool operator<(marker_type o) const { return marker < o; }
};
friend bool operator<(marker_type a, const Pair &o);
template <typename T, typename = std::enable_if<is_derived_from_Base_v<T>>>
struct Witness {
static void marker() {}
};
std::vector<Pair> m_objects;
public:
template <class Derived, class =
std::enable_if_t<is_derived_from_Base_v<Derived>>>
void insert(std::unique_ptr<Derived> &&obj) {
auto constexpr marker = &Witness<Derived>::marker;
auto it = std::lower_bound(m_objects.begin(), m_objects.end(), marker);
if (it != m_objects.end() && it->marker == marker)
throw std::logic_error("Attempting to insert an object of duplicate type");
m_objects.emplace(it, std::move(obj), marker);
}
template <typename Derived, typename Fun,
class = std::enable_if_t<is_derived_from_Base_v<Derived>>>
void apply(Fun fun) const {
auto constexpr marker = &Witness<Derived>::marker;
auto it = std::lower_bound(m_objects.begin(), m_objects.end(), marker);
if (it == m_objects.end() || it->marker != marker)
throw std::runtime_error("No object found to apply the function to");
std::invoke(fun, *static_cast<Derived*>(it->base.get()));
}
template <typename Fun,
class = std::enable_if_t<is_derived_from_Base_v<
typename function_traits<std::decay_t<Fun>>::arg0_class>>>
void apply(Fun fun) const {
using arg0_class = typename function_traits<std::decay_t<Fun>>::arg0_class;
apply<arg0_class>(std::move(fun));
}
};
bool operator<(void(*a)(), const UniqueTypeObjects::Pair &o)
{ return a < o.marker; }
char lastInvoked;
int main() {
struct A : Base {
void methodA() { lastInvoked = 'A'; }
};
struct B : Base {
void methodB() { lastInvoked = 'B'; }
};
UniqueTypeObjects uto;
uto.insert(std::make_unique<A>());
uto.insert(std::make_unique<B>());
assert(!lastInvoked);
uto.apply([](A &a){ a.methodA(); });
assert(lastInvoked == 'A');
uto.apply([](B &b){ b.methodB(); });
assert(lastInvoked == 'B');
}
But I still don't think it's necessary. If you truly have O(1) requirement, e.g. some sort of a realtime system, or system with deterministic execution timing, then the opt_tuple solution or its equivalent is the one you should use. Otherwise - good luck with the paperwork and test plans to ensure that UniqueTypeObjects works. I wrote the thing and even I wouldn't allow it in a realtime or hi-reliability codebase I maintained. Nothing beats static type safety and ensuring correctness by design, and you get that with the tuple approach (or its equivalent with a custom class).

C++ generic factory with multiple constructor signatures?

Has anyone ever combined the classic generic factory by Andrei Alexandrescu (page 208 of Chapter 8 in Modern C++ Design) with the 'multifunction' capabilities of Boost.TypeErasure? That is, the flexibility to have several creator function signatures that vary with respect to number and type of parameters (but still have the same return type and are known at compile time).
In other words, how to combine this slightly simplified generic Factory:
#include <map>
#include <utility>
#include <stdexcept>
template <class AbstractProduct, typename IdentifierType, typename ProductCreator>
class Factory
{
public:
bool Register(const IdentifierType& id, ProductCreator creator) {
return associations_.emplace(id, creator).second;
}
bool Unregister(const IdentifierType& id) {
return associations_.erase(id) == 1;
}
template <typename... Arguments>
AbstractProduct CreateObject(const IdentifierType& id, Arguments&& ... args) {
auto i = associations_.find(id);
if (i != associations_.end()) {
return (i->second)(std::forward<Arguments>(args)...);
}
throw std::runtime_error("Creator not found.");
}
private:
std::map<IdentifierType, ProductCreator> associations_;
};
with this (incomplete) function type erasure 'pattern':
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/callable.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/variant.hpp>
template<class... Sig>
using multifunction = any< mpl::vector< copy_constructible<>, typeid_<>, relaxed, callable<Sig>... > >;
using variant_type = boost::make_recursive_variant< void, double, ... >::type;
using function_type = multifunction<AbstractProduct(void), AbstractProduct(double), AbstractProduct(double, double)>;
class variant_handler
{
public:
void handle(const variant_type& arg) {
boost::apply_visitor(impl, arg);
}
void set_handler(function_type f) {
impl.f = f;
}
private:
struct dispatcher : boost::static_visitor<void>
{
template<class T>
void operator()(const T& t) { f(t); }
// For a vector, we recursively operate on the elements
void operator()(const vector_type& v)
{
boost::for_each(v, boost::apply_visitor(*this));
}
function_type f;
};
dispatcher impl;
};
So that ultimately one can use it like:
Factory<Arity*, int, ???> factory;
factory.Register(0, boost::bind( boost::factory<Nullary *>() ));
factory.Register(1, boost::bind( boost::factory<Unary *>(), _1 ));
auto x = factory.CreateObject(0);
auto y = factory.CreateObject(1, 0.5);
I haven't found an existing implementation in the wild, and I am currently stuck in my own attempt to make it. My first attempt made the mistake of trying to store the result of boost::bind() in the function_type, which resulted the same error to this SO question. I suspect the answer will require moving the ProductCreator template parameter to the Register function and doing something there.
So I guess I am ultimately looking for a full, working implementation of a generic multifunction factory, which may already exist and I just overlooked it. But any help with just getting it together would be really appreciated.
I would prefer a C++11 solution, but obviously C++14 is better than none, etc.
Thanks in advance for any help with this!
OK, I have a slightly ugly solution that doesn't use Boost.TypeErasure, it is C++14, but it does provide essentially the same functionality. It's multi-tiered, so the id numbering is per-factory (but you could number uniquely too).
I'll write more soon, but I really have to go to sleep right now...
#include <boost/functional/factory.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <cassert>
#include <map>
#include <tuple>
#include <type_traits>
#include <utility>
template <class AbstractProduct, typename IdentifierType, typename... ProductCreators>
class Factory
{
using AssociativeContainers = std::tuple<std::map<IdentifierType, boost::function<ProductCreators>>...>;
public:
template <typename Product, typename... Arguments>
bool Register(const IdentifierType& id, boost::function<Product(Arguments...)> creator) {
auto &foo = std::get<std::map<IdentifierType, boost::function<AbstractProduct(const Arguments&...)>>>(associations_);
return foo.emplace(id, creator).second;
}
// This function left as an exercise to the reader...
bool Unregister(const IdentifierType& id) {
return associations_.erase(id) == 1;
}
template <typename... Arguments>
AbstractProduct CreateObject(const IdentifierType& id, Arguments&& ... args) const {
auto const &foo = std::get<std::map<IdentifierType, boost::function<AbstractProduct(const Arguments&...)>>>(associations_);
auto const i = foo.find(id);
if (i != foo.end()) {
return (i->second)(std::forward<Arguments...>(args)...);
}
throw std::runtime_error("Creator not found.");
}
private:
AssociativeContainers associations_;
};
struct Arity {
virtual ~Arity() = default;
};
struct Nullary : Arity {};
struct Unary : Arity {
Unary() {}
Unary(double x) : x(x) {}
double x;
};
int main(void)
{
Factory<Arity*, int, Arity*(), Arity*(const double&)> factory;
factory.Register(0, boost::function<Arity*()>{boost::factory<Nullary*>()} );
factory.Register(1, boost::function<Arity*(const double&)>{boost::bind(boost::factory<Unary*>(), _1)});
auto x = factory.CreateObject(1, 2.0);
assert(typeid(*x) == typeid(Unary));
x = factory.CreateObject(0);
assert(typeid(*x) == typeid(Nullary));
}
Hallelujah, I found a solution using Boost.Variant but no type erasure. I think this is much better than my earlier answer, as:
Creator id is unique.
CreateObject supports implicit conversion of parameters to constructor.
The same limitation that the constructors must take const& parameters exists.
I have simplified the overall design somewhat to focus on the essential behaviour. What's missing is the policy for error handling and configurable associative container type, which should be additional class template parameters. I have also left some minimal debugging code in so that you can see for yourself that it works when you test it out.
#include <boost/functional/factory.hpp>
#include <boost/function.hpp>
#include <boost/variant.hpp>
#include <map>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
// Just for debugging.
#include <cassert>
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
// Tuple manipulation.
template <typename Signature>
struct signature_impl;
template <typename ReturnType, typename... Args>
struct signature_impl<ReturnType(Args...)>
{
using return_type = ReturnType;
using param_types = std::tuple<Args...>;
};
template <typename T>
using signature_t = signature_impl<T>;
template <std::size_t... Ints>
struct indices {};
template <std::size_t N, std::size_t... Ints>
struct build_indices : build_indices<N-1, N-1, Ints...> {};
template <std::size_t... Ints>
struct build_indices<0, Ints...> : indices<Ints...> {};
template <typename Tuple>
using make_tuple_indices = build_indices<std::tuple_size<typename std::remove_reference<Tuple>::type>::value>;
// The multiple-signature factory.
template <class AbstractProduct, typename IdentifierType, typename... ProductCreators>
class multifactory
{
using functions = boost::variant<boost::function<ProductCreators>...>;
std::map<IdentifierType, functions> associations_;
template <typename Signature>
struct dispatch_foo
{
template <typename CreateArgs, std::size_t... Indices>
typename std::enable_if<std::is_convertible<CreateArgs, typename signature_t<Signature>::param_types>::value, AbstractProduct>::type
static apply(boost::function<Signature> const &f, CreateArgs && t, indices<Indices...>)
{
return f(std::get<Indices>(std::forward<CreateArgs>(t))...);
}
template <typename CreateArgs, std::size_t... Indices>
typename std::enable_if<!std::is_convertible<CreateArgs, typename signature_t<Signature>::param_types>::value, AbstractProduct>::type
static apply(boost::function<Signature> const &, CreateArgs &&, indices<Indices...>)
{
return nullptr;
}
};
template <typename... CreateArguments>
struct dispatcher : boost::static_visitor<AbstractProduct>
{
std::tuple<CreateArguments...> args;
dispatcher(CreateArguments const&... args) : args{std::forward_as_tuple(args...)} {}
template <typename Signature>
AbstractProduct operator()(boost::function<Signature> const &f) const
{
int status;
std::cout << "visitor: " << abi::__cxa_demangle(typeid(Signature).name(), nullptr, 0, &status) << "\n";
return dispatch_foo<Signature>::apply(f, args, make_tuple_indices<std::tuple<CreateArguments...>>{});
}
};
public:
template <typename ProductCreator>
bool Register(IdentifierType id, ProductCreator &&creator) {
return associations_.emplace(id, std::forward<ProductCreator>(creator)).second;
}
bool Unregister(const IdentifierType& id) {
return associations_.erase(id) == 1;
}
template <typename... Arguments>
AbstractProduct CreateObject(const IdentifierType& id, Arguments const& ... args) {
auto i = associations_.find(id);
if (i != associations_.end()) {
dispatcher<Arguments...> impl(args...);
return boost::apply_visitor(impl, i->second);
}
throw std::runtime_error("Creator not found.");
}
};
struct Arity {
virtual ~Arity() = default;
};
struct Nullary : Arity {};
struct Unary : Arity {
Unary() {} // Also has nullary ctor.
Unary(int) {}
};
int main(void)
{
multifactory<Arity*, int, Arity*(), Arity*(const int&)> factory;
factory.Register(0, boost::function<Arity*()>( boost::factory<Nullary*>() ));
factory.Register(1, boost::function<Arity*(const int&)>(boost::factory<Unary*>()) );
auto a = factory.CreateObject(0);
assert(a);
assert(typeid(*a) == typeid(Nullary));
auto b = factory.CreateObject(1, 2);
assert(b);
assert(typeid(*b) == typeid(Unary));
}

restricting the types using templates in vc++

As far my understanding goes I want to restrict only 2 types int and string for the following class, just like in java template definition with extends.
template<typename T>
typename std::enable_if<std::is_same<T,int>::value || std::is_same<T,string>::value>::type
class ExchangeSort
{
public:
void bubbleSort(T buffer[], int s);
void print(T buffer[], int s);
void bubbleSort(const vector<T>& vec);
};
But if I'm instantiating like below
ExchangeSort<int>* sortArray = new ExchangeSort<int>;
I'm getting errors for the above line ExchangeSort is undefined. What is the problem ?
SFINAE can be used to conditionally disable function overloads or template specialisations. It makes no sense to try to use it to disable a class template, since class templates cannot be overloaded. You'll be better off using a static assertion:
template<typename T>
class ExchangeSort
{
static_assert(std::is_same<T,int>::value || std::is_same<T,string>::value, "ExchangeSort requires int or string");
public:
// The rest as before
As to the errors you were getting, the code didn't make syntactic sense. enable_if can only appear where a type is expected. With functions, it's often used to wrap the return type, in which case it's syntactically similar to what you wrote. But with classes, there's no type between template and the class definition.
Here's another way which allows the possibility of adding further specialisations down the line:
#include <type_traits>
#include <vector>
#include <string>
//
// Step 1 : polyfill missing c++17 concepts
//
namespace notstd {
template<class...> struct disjunction : std::false_type { };
template<class B1> struct disjunction<B1> : B1 { };
template<class B1, class... Bn>
struct disjunction<B1, Bn...>
: std::conditional_t<bool(B1::value), B1, disjunction<Bn...>> { };
}
//
// Step 2 : create a test to see if a type is in a list
//
namespace detail {
template<class T, class...Us>
struct is_one_of : notstd::disjunction< std::is_same<T, Us>... > {};
}
template<class T, class...Us>
static constexpr auto IsOneOf = detail::is_one_of<T, Us...>::value;
//
// Step 3 : declare the default specialisation, but don't define it
//
template<class T, typename Enable = void>
struct ExchangeSort;
//
// Step 4 : define the specialisations we want
//
template<typename T>
class ExchangeSort<T, std::enable_if_t<IsOneOf<T, int, std::string>>>
{
public:
void bubbleSort(T buffer[], int s);
void print(T buffer[], int s);
void bubbleSort(const std::vector<T>& vec);
};
//
// Test
//
int main()
{
auto esi = ExchangeSort<int>();
auto ess = ExchangeSort<std::string>();
// won't compile
// auto esd = ExchangeSort<double>();
}

Achieve functor overloading through composition

Given some existing functors:
struct incr {
int operator()(int x) const { return x + 1; }
};
struct rep_str {
std::string operator()(const std::string& s) const { return s + s; }
};
I'm wondering if it's possible to achieve something like this:
auto f = overload<incr, rep_str>();
f(1); // returns 2
f("hello"); // returns "hellohello"
Multiple overloads may look like:
auto f = overload<fa, fb, fc, ...>();
// or...
auto g = overload<fa, overload<fb, overload<fc, ...>>>();
I'm thinking maybe use SFINAE with std::result_of_t or something like that, but haven't figured out how.
You don't need anything too fancy: just inherit from all the arguments and use using-declarations to bring in operator() from the base classes. However, in the variadic case, you can't have a pack expansion in a using-declaration, so you have to use a recursive approach, like so:
template <class... Ts>
struct overload {}; // only used for empty pack
template <class T>
struct overload<T> : private T {
using T::operator();
};
template <class T1, class T2, class... Ts>
struct overload<T1, T2, Ts...> : private T1, overload<T2, Ts...> {
using T1::operator();
using overload<T2, Ts...>::operator();
};
Brian's answer is better, IMHO, but since I worked on it, here's mine:
#include <type_traits>
#include <utility>
template <typename... Fns>
struct overload;
template <typename Fn, typename... Fns>
struct overload<Fn, Fns...>
{
template <typename... T>
std::result_of_t<Fn(T...)> operator()(T && ... args) const {
return Fn()(std::forward<T>(args)...);
}
using next = overload<Fns...>;
template <typename... T>
std::result_of_t<next(T...)> operator()(T && ... args) const {
return next()(std::forward<T>(args)...);
}
};
this can be done using template specialization:
#include <string>
#include <iostream>
template <typename...Args>
struct overload{
};
template <> struct overload<int>{
int operator()(int x) const { return x + 1; }
};
template <> struct overload< std::string>{
std::string operator()(const std::string& s) const { return s + s; }
};
template <typename...Args >
auto f(Args...arg){
overload<Args...> func;
return func(arg...);
}
int main()
{
std::cout << f(3) << std::endl << f(std::string("Hello"));
}
Note: two answers by #Brian and #md5i more general and elegant and perfect and better than this.