I'm trying to implement a reader functor in C++.
Corresponding Haskell definition is fmap :: (a -> b) -> (r -> a) -> (r -> b)
My C++ version is:
template<class A, class B, class R>
B fmap(const std::function<B(A)> &funcA, const std::function<A(R)> &funcR) {
return funcA(funcR());
}
std::string function_1(int n);
double function_2(std::string s);
fmap(function_2, function_1);
The error is:
note: candidate template ignored: could not match 'function<type-parameter-0-1 (type-parameter-0-0)>' against 'double (std::__1::basic_string<char>)'
B fmap(const std::function<B(A)> &funcA, const std::function<A(R)> &funcR) {
What is the correct way to implement fmap function?
You can do this with a neat template conversion trick from Template type deduction with std::function
#include <functional>
#include <iostream>
#include <string>
using namespace std;
template<class T>
struct AsFunction
: public AsFunction<decltype(&T::operator())>
{};
template<class ReturnType, class... Args>
struct AsFunction<ReturnType(Args...)> {
using type = std::function<ReturnType(Args...)>;
};
template<class ReturnType, class... Args>
struct AsFunction<ReturnType(*)(Args...)> {
using type = std::function<ReturnType(Args...)>;
};
template<class Class, class ReturnType, class... Args>
struct AsFunction<ReturnType(Class::*)(Args...) const> {
using type = std::function<ReturnType(Args...)>;
};
template<class F>
auto toFunction(F f) -> typename AsFunction<F>::type {
return { f };
}
template<class A, class B, class R>
B fmap(const std::function<B(A)>& funcA, const std::function<A(R)>& funcR, R value) {
return funcA(funcR(value));
}
template <class T>
auto ToFunction(T t) {
return t;
}
std::string function_1(int n) {
return ""s;
}
double function_2(std::string s) {
return 0.0;
}
int main() {
fmap(toFunction(function_2), toFunction(function_1), 5);
return 0;
}
The issue is that template deduction works with exact match on type, without conversions.
You are passing in function pointers, which is not the same type as std::function, so deduction of the template parameters will fail.
The correct way is to take in the callables as template arguments. This ensures deduction will work. A lot of times you don't need to check the signature of the callable, since if it's used in the function you will get a compile time error if it's used in the wrong way.
If you still want to check the signature it's not very hard to do with a type trait.
#include <string>
template<class A, class B>
B fmap(A a, B b) {
return a(b(std::string{}));
}
std::string function_1(int n);
double function_2(std::string s);
fmap(function_2, function_1);
Bartosz Milewski's book "Category Theory for Programmers" (2014-19)
https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/
gives an example of the Writer functor in C++ ... and it's a simpler step from there to produce the Reader functor:
#include <string>
#include <functional>
using namespace std;
template<class R, class A, class B>
function<B(R)> Reader(function<A(R)> m1, function<B(A)> m2)
{
return [m1,m2] (R r) { return m2(m1(r)); };
}
// example
string repeat(string x) {return x+x;}
string i_to_s( int x) {return to_string(x);}
string process(int x) {
return Reader<int, string, string>(i_to_s, repeat)(x);}
Related
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).
I'd like to have a class that gets in it's Ctor unlimited parameters of the same type, and stores them into a vector. It should look like that:
class A(int a, int b, **N time parameter of type T**)
: data(**vector will get N times type T**)
{
}
protected:
vector<T> data;
How should I implement it? Solution could be in c++11/14
I got a few errors such as "parameter packs not expanded with ‘…' ", etc..
This code sample might be useful:
#include <vector>
#include <utility>
template<typename T>
class MyClass {
public:
template<typename ...Args>
MyClass(int a, int b, Args&& ...args) :data{ std::forward<Args>(args)... } {}
private:
std::vector<T> data;
};
int main() {
MyClass<char> sample(1, 2, 'a', 'b');
return 0;
}
[EDIT]: Added std::forward, added missing include for utility
Assuming that T could be anything, even something quite large or non-copyable, we'd want to:
preserve efficiency with perfect forwarding.
check types.
std::initializer_list satisfies 2 but not 1.
Simple variadic template expansion satisfies 1 and not 2.
This solution uses variadic template expansion and enable_if to enforce type compatibility.
#include <vector>
#include <utility>
#include <string>
namespace detail
{
constexpr bool all()
{
return true;
}
template<class...Rest>
constexpr bool all(bool b, Rest...rest)
{
return b and all(rest...);
};
}
template<class T>
class A
{
public:
using value_type = T; // say
template<class...Rest,
std::enable_if_t<detail::all(std::is_convertible<Rest, value_type>::value...)>* = nullptr>
A(int a, int b, Rest&&...rest)
: a_(a), b_(b)
{
this->fill(std::forward_as_tuple(std::forward<Rest>(rest)...),
std::make_index_sequence<sizeof...(Rest)>());
}
private:
template<class Tuple, std::size_t...Is>
void fill(Tuple&& t, std::index_sequence<Is...> seq)
{
data_.reserve(seq.size());
using expand = int[];
void(expand{ 0,
(data_.push_back(std::move(std::get<Is>(t))), 0)...
});
}
private:
int a_, b_;
std::vector<value_type> data_;
};
int main()
{
using namespace std::literals;
auto a = A<double>(1, 2, 4.3, 5.5, 6.6);
auto b = A<std::string>(1, 2, "the", "cat"s, "sat on the mat");
// error: no matching constructor...
// auto err = A<std::string>(1, 2, "the", "cat"s, 0.1);
}
Here you go:
#include <iostream>
#include <vector>
template<class T>
struct V
{
V(int n, std::initializer_list<T> l)
: data(l)
{
(void) n;
}
std::vector<T> data;
};
int main()
{
V<int> v(0,{1,2,3});
}
This is not a perfect example since one needs to construct an object with the weird syntax (n, {optional, arguments, of, same, type}) but it does provide wanted behavior.
The following example is similar to fr3nzy90's, but with the coming C++17 it will allow automatic deduction of T from the constructor arguments:
template <class T>
class MyContainer {
private:
std::vector<T> data;
public:
// Take the first T value explicitly so it can be used to deduce
// T from the constructor arguments (C++17 feature).
template <class... Ts>
MyContainer(int a, int b, T const & tval, Ts const &... tvals) :
data{tval, tvals...} {
…
}
// Special case, empty list, no implicit type deduction, because
// there is no T value to deduce it from.
MyContainer(int a, int b) {
…
}
};
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.
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));
}
Consider this code:
#include <iostream>
using namespace std;
class hello{
public:
void f(){
cout<<"f"<<endl;
}
virtual void ff(){
cout<<"ff"<<endl;
}
};
#define call_mem_fn(object, ptr) ((object).*(ptr))
template<R (C::*ptr_to_mem)(Args...)> void proxycall(C& obj){
cout<<"hello"<<endl;
call_mem_fn(obj, ptr_to_mem)();
}
int main(){
hello obj;
proxycall<&hello::f>(obj);
}
Of course this won't compile at line 16, because the compiler doesn't know what R, C and Args, are. But there's another problem: if one tries to define those template parameters right before ptr_to_mem, he runs into this bad situation:
template<typename R, typename C, typename... Args, R (C::*ptr_to_mem)(Args...)>
// ^variadic template, but not as last parameter!
void proxycall(C& obj){
cout<<"hello"<<endl;
call_mem_fn(obj, ptr_to_mem)();
}
int main(){
hello obj;
proxycall<void, hello, &hello::f>(obj);
}
Surprisingly, g++ does not complain about Args not being the last parameter in the template list, but anyway it cannot bind proxycall to the right template function, and just notes that it's a possible candidate.
Any solution? My last resort is to pass the member function pointer as an argument, but if I could pass it as a template parameter it would fit better with the rest of my code.
EDIT:
as some have pointed out, the example seems pointless because proxycall isn't going to pass any argument. This is not true in the actual code I'm working on: the arguments are fetched with some template tricks from a Lua stack. But that part of the code is irrelevant to the question, and rather lengthy, so I won't paste it here.
You could try something like this:
template <typename T, typename R, typename ...Args>
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args)
{
return (obj.*mf)(std::forward<Args>(args)...);
}
Usage: proxycall(obj, &hello::f);
Alternatively, to make the PTMF into a template argument, try specialization:
template <typename T, T> struct proxy;
template <typename T, typename R, typename ...Args, R (T::*mf)(Args...)>
struct proxy<R (T::*)(Args...), mf>
{
static R call(T & obj, Args &&... args)
{
return (obj.*mf)(std::forward<Args>(args)...);
}
};
Usage:
hello obj;
proxy<void(hello::*)(), &hello::f>::call(obj);
// or
typedef proxy<void(hello::*)(), &hello::f> hello_proxy;
hello_proxy::call(obj);
In modern C++ one can use template<auto> and generic lambda-wrapper:
#include <utility>
#include <functional>
template<auto mf, typename T>
auto make_proxy(T && obj)
{
return [&obj] (auto &&... args) { return (std::forward<T>(obj).*mf)(std::forward<decltype(args)>(args)...); };
}
struct R {};
struct A {};
struct B {};
struct Foo
{
R f(A &&, const B &) { return {}; }
//R f(A &&, const B &) const { return {}; }
};
int main()
{
Foo foo;
make_proxy<&Foo::f>(foo)(A{}, B{});
//make_proxy<static_cast<R (Foo::*)(A &&, const B &) const>(&Foo::f)>(std::as_const(foo))(A{}, B{});
//make_proxy<static_cast<R (Foo::*)(A &&, const B &)>(&Foo::f)>(foo)(A{}, B{});
}
If there are overloadings one should to specify member function type explicitly as in commented code.