Thin replacement for fat std::function - c++

I'm trying to pack my object to 64 bytes (homegrown properties), and I need to save getter and setter member functions.
I really like std::function but is way big:
sizeof(std::function<int(void)>) gives 40 bytes (VS2017, x64).
I'm trying to figure out is there any thin version of std::function 16 bytes large and without extra allocations inside?
Update: Solution looks like this, it takes 16 bytes (x64) for two member functions.
Member function pointers became template argument so they take nothing, stored just object pointer and vptr.
Thanks to #Yakk.
class Property
{
public:
virtual ~Property() {}
virtual QVariant value() const = 0;
virtual void setValue(const QVariant& value) = 0;
};
template<typename TYPE,
typename CLASS,
TYPE(CLASS::*get)() const,
void(CLASS::*set)(const TYPE &)>
class PropertyValue : public Property
{
public:
PropertyValueGet() = delete;
PropertyValueGet(PropertyValueGet const& ) = delete;
PropertyValueGet& operator=(PropertyValueGet const& ) = delete;
PropertyValueGet(CLASS* object) : m_object(object) {}
TYPE getValue() const {
return (m_object->*get)();
}
void setValue(const TYPE& value) {
(m_object->*set)(value);
}
// Property implementation
//
virtual QVariant value() const final {
QVariant v = QVariant::fromValue<TYPE>(getValue());
return v;
}
virtual void setValue(const QVariant& value) final {
setValue(value.value<TYPE>());
}
private:
CLASS* m_object = nullptr;
};

The type of m_getter is decltype(m_getter).
Using std::mem_fn in Modern C++ is a bad idea - lambda expressions are a cleaner and more transparent (both to the developer and the compiler) way of binding arguments.
Stephan T. Lavavej, in the talk “functional: What's New, And Proper Usage", mentions some drawbacks of std::bind and std::mem_fn compared to lambdas:
You should use a lambda expression instead. E.g.:
auto my_getter = [](Foo& foo){ return foo.getter(); };
Foo some_foo;
my_getter(some_foo);
or
Foo some_foo;
auto my_getter = [&some_foo](){ return some_foo.getter(); };
my_getter();

&Foo::getter has a type, it is TYPE(Foo::*)(void), which is most likely a smaller type than std::function<TYPE(void)>. Similarly &Foo::setter is a void(Foo::*)(TYPE).
But you can get even smaller, by discarding the errant notion that getters and setters are encapsulation, with &Foo::field, which is a TYPE Foo::*.
template<typename T, typename C>
struct Property
{
Property(T C::*member) : member(member) {}
T & get(C & c) { return std::invoke(member, c); }
void set(C & c, T & t) { std::invoke(member, c) = t; }
private:
T C::* member;
}
Alternately accompanying an instance
template<typename T, typename C>
struct Property
{
Property(T C::*member, C & instance) : member(member), instance(instance) {}
T & get() { return std::invoke(member, instance); }
void set(T & value) { std::invoke(member, instance) = value; }
private:
T C::* member;
C & instance;
}

The OP has clarified that the members used are fixed:
template<class T>
struct generic_property {
virtual T getValue() const = 0;
virtual void setValue(T const&) = 0;
protected:
virtual ~generic_property() {}
};
template<class D, class T, void(D::*set)(T const&), T(D::*get)() const>
struct property:generic_property<T> {
T getValue() const final {
return (self->*get)();
}
void setValue(T const& t) final {
(self->*set)(t);
}
property( D* s ):self(s) {}
// cannot usually safely copy/move/trivial:
property() = delete;
property( property const& ) = delete;
property& operator=( property const& ) = delete;
private:
D* self = 0;
};
struct Bob {
void setFoo( int const& i ) { std::cout << i << " set\n"; }
int getFoo() const { std::cout << 42 << " get\n"; return 42; }
property<Bob, int, &Bob::setFoo, &Bob::getFoo> foo;
Bob():foo(this) {}
};
each property takes up 1 pointers worth of space (so 32 to 64 bits, or 4-8 bytes, depending on the bit-width of the OS).
Adding virtual and generic_property<T> makes it take up another pointer's worth of space.
live example.
We could type erase manually in generic_property instead of by virtual inheritance.

This is a c++17 answer, because doing this in c++11 is really annoying.
Here is a "simple" stateless view-only std::function.
// utility tag type for dispatching
template<class Tag>
struct tag_t {};
// helper type to find the "caller" function pointer used to erase invoke:
template<class Sig>
struct caller_type;
template<class R, class...Args>
struct caller_type<R(Args...)> {
using type = R(*)(void*, Args&&...);
};
template<class Sig>
using caller = typename caller_type<Sig>::type;
// make a caller<Sig> that type erases calling T with Sig:
template<class T, class Sig>
struct make_caller;
template<class T, class R, class...Args>
struct make_caller<T, R(Args...)> {
caller<R(Args...)> operator()() const {
return [](void* ptr, Args&&...args)->R {
return (*static_cast<T*>(ptr))( std::forward<Args>(args)... );
};
}
};
template<class T, class...Args>
struct make_caller<T, void(Args...)> {
caller<void(Args...)> operator()() const {
return [](void* ptr, Args&&...args)->void {
(*static_cast<T*>(ptr))( std::forward<Args>(args)... );
};
}
};
// provides operator() overload compatible with Sig,
// then dispatches the call down through a derived type D:
template<class D, class Sig>
struct call_dispatch;
template<class D, class R, class...Args>
struct call_dispatch<D, R(Args...)> {
R operator()(Args...args)const {\
auto* caller = self()->get_caller(tag_t<R(Args...)>{});
return (*caller)( self()->pvoid(), std::forward<Args>(args)... );
}
auto self() { return static_cast<D*>(this); }
auto self() const { return static_cast<D const*>(this); }
};
// stores a function pointer to invoke Sig
template<class Sig>
struct call_storage {
caller<Sig> f = nullptr;
template<class T>
static call_storage make() {
return {make_caller<T, Sig>{}()};
}
caller<Sig> get_caller( tag_t<Sig> ) const { return f; }
};
// a table of such function pointers
template<class...Sig>
struct call_vtable:call_storage<Sig>... {
template<class T>
static call_vtable make() {
return {call_storage<Sig>::template make<T>()...};
}
using call_storage<Sig>::get_caller...;
};
// overload helper to dispatch to correct Sig:
template<class D, class...Sig>
struct call_dispatcher:
call_dispatch<D, Sig>...
{
using call_dispatch< D, Sig >::operator()...;
};
// Erases invoking but not storing an arbitrary type T
// with all of ...Sig. Stores the invokers inside itself,
// not in an external vtable, to increase locality at the cost
// of per-instance size:
template<class... Sig>
struct call_view_t:
private call_vtable<Sig...>,
call_dispatcher< call_view_t<Sig...>, Sig... >
{
template<class F,
std::enable_if_t<!std::is_same<std::decay_t<F>, call_view_t>{}, bool> =true
>
call_view_t( F&& f ):
call_vtable<Sig...>( call_vtable<Sig...>::template make<std::decay_t<F>>() ),
ptr( std::addressof(f) )
{}
call_view_t()=default;
call_view_t(call_view_t const&)=default;
call_view_t& operator=(call_view_t const&)=default;
explicit operator bool() const { return ptr != nullptr; }
void* pvoid() const { return ptr; }
using call_vtable<Sig...>::get_caller;
private:
void* ptr = 0;
};
it requires 2 pointers, one to store non-owning state and one to store an invoker (it also supports any number of signatures on the thing to invoke).
We can create a new call_view type that instead of storing a ptr*, stores a block of memory; in that block, it placement new's the state of the F passed in and pvoid() returns a pointer to it.
Unless you restrict yourself to trivial destruction and copy/move, you'll also have to store pointers to functions on how to do that.
As call_impl only varies based on the type of thing stored and not its value, we can store the f's in a vtable and only inherit from call_dispatch. Inside that vtable we can store copy/move/destroy of our copy of F.
This permits us to have a trim std::function with state that only requires 1 pointer overhead over the storage of whatever state you want to put in the std::function.
Note that the above code probably has typos, and doesn't solve your problem. It has 9/10 of the pieces to solve your problem.
// a vtable that represents "I can be copied or moved and destroyed":
struct copyable_vtable {
void(*dtor)(void*)=0;
void(*copy)(void* dest, void const* src)=0;
void(*move)(void* dest, void* src)=0;
template<class T>
static copyable_vtable make() {
return {
[](void* ptr){ static_cast<T*>(ptr)->~T(); },
[](void* dest, void const* src){
::new( dest ) T(*static_cast<T const*>(src));
},
[](void* dest, void * src){
::new( dest ) T(std::move(*static_cast<T const*>(src)));
}
};
}
};
// the vtable that our "small function" needs:
template<class...Sig>
struct small_func_vtable:
copyable_vtable,
call_vtable<Sig...>
{
template<class T>
static small_func_vtable make() {
return {
copyable_vtable::template make<T>(),
call_vtable<Sig...>::template make<T>()
};
}
template<class T>
static small_func_vtable const* get() {
static const auto vtable = make<T>();
return &vtable;
}
};
// bundles up the size and alignment requirements:
template<std::size_t S=sizeof(void*)*3, std::size_t A=alignof(void*)>
struct size_params {
enum { size = S, align = A };
};
// A small stack allocated std::function that refuses to get bigger
// If you try to construct it with something larger, you get
// a static assert failure. Also supports arbitrary number of
// overloads of ():
template<class Size, class...Sig>
struct small_function:
call_dispatcher< small_function<Size, Sig...>, Sig... >
{
private:
small_func_vtable<Sig...> const* vtable = 0;
mutable std::aligned_storage_t< Size::size, Size::align > data;
public:
template<class F,
std::enable_if_t<!std::is_same<std::decay_t<F>, small_function>{}, bool> =true
>
small_function( F&& f )
{
static_assert( sizeof(std::decay_t<F>)<=Size::size );
static_assert( alignof(std::decay_t<F>)<=Size::align );
::new( (void*)&data ) std::decay_t<F>( std::forward<F>(f) );
vtable = small_func_vtable<Sig...>::template get<std::decay_t<F>>();
}
small_function()=default;
// we could refactor this into base class:
small_function(small_function const& o) {
if (!o.vtable) return;
o.vtable->copy( pvoid(), o.pvoid() );
vtable = o.vtable;
}
small_function(small_function&& o) {
if (!o.vtable) return;
o.vtable->move( pvoid(), o.pvoid() );
vtable = o.vtable;
}
small_function& operator=(small_function const& o) {
if (this == &o) return *this;
if (vtable) {
vtable->dtor(pvoid());
vtable = nullptr;
}
if (o.vtable) {
o.vtable->copy( pvoid(), o.pvoid() );
vtable = o.vtable;
}
return *this;
}
small_function& operator=(small_function&& o) {
if (this == &o) return *this;
if (vtable) {
vtable->dtor(pvoid());
vtable = nullptr;
}
if (o.vtable) {
o.vtable->move( pvoid(), o.pvoid() );
vtable = o.vtable;
}
return *this;
}
// use null vtable to determine if we are empty:
explicit operator bool() const { return vtable != nullptr; }
// these must be visible to dispatch system. I think
// they are harmless to expose to end users, so I don't bother
// with making them private and friending dispatch system:
void* pvoid() const { return &data; }
template<class S>
caller<S> get_caller(tag_t<S> t) const {
if (!vtable) return nullptr;
return vtable->get_caller(t);
}
};
template<class...Sig>
using simple_small_function = small_function< size_params<>, Sig... >;
and try simple_small_function.
Live example.

Let's look at what we need for std::function:
A pointer for the list of how to copy, destroy, and invoke the payload. Knowledge of the targets type and how to retrieve it is a bonus, and extra cost per type is marginal (none per instance).
The target. To avoid rampant allocating, there should be space for at least a member-function-pointer. Unfortunately, the conforming format MSVC uses is a whomping 4 pointers big (they use different smaller non-conforming ones in different situations). Other ABIs use smaller ones for full effect.
So, that's 5 pointers worth => 5*8 = 40 Bytes on 64 bit Windows as a minimum to accomodate member-function-pointers.

Related

Type agnostic getter methods

I'm writing a client for a system that returns values of natural types in random order (some can be int, others float, others string [well, almost natural]). The problem is, I don't know what type a value will be at compile time.
Since I don't know the type of the value to be returned until after the remote system has been queried, what is the best way to provide a uniform interface that allows a user of the client library to extract the value in the right type?
If querying the remote system once returns a string, I'd like my get_value() to return a string. If an int, make it return an int. Alternatively, how to have the client library call the getter with the right type?
I guess templates with type hinting would be a good way to achieve this?
Examine boost or std variant if there is a finite list of supported types.
If not a finite list, boost or std any (or a variant containing an any).
You can find other implementations as well. The std versions are in C++17.
A simplified version of variant could probably be written in a 100 or two lines of code.
Here is a crude C++14 variant:
constexpr std::size_t max() { return 0; }
template<class...Ts>
constexpr std::size_t max( std::size_t t0, Ts...ts ) {
return (t0<max(ts...))?max(ts...):t0;
}
template<class T0, class...Ts>
struct index_of_in;
template<class T0, class...Ts>
struct index_of_in<T0, T0, Ts...>:std::integral_constant<std::size_t, 0> {};
template<class T0, class T1, class...Ts>
struct index_of_in<T0, T1, Ts...>:
std::integral_constant<std::size_t,
index_of_in<T0, Ts...>::value+1
>
{};
struct variant_vtable {
void(*dtor)(void*) = 0;
void(*copy)(void*, void const*) = 0;
void(*move)(void*, void*) = 0;
};
template<class T>
void populate_vtable( variant_vtable* vtable ) {
vtable->dtor = [](void* ptr){ static_cast<T*>(ptr)->~T(); };
vtable->copy = [](void* dest, void const* src){
::new(dest) T(*static_cast<T const*>(src));
};
vtable->move = [](void* dest, void* src){
::new(dest) T(std::move(*static_cast<T*>(src)));
};
}
template<class T>
variant_vtable make_vtable() {
variant_vtable r;
populate_vtable<T>(&r);
return r;
}
template<class T>
variant_vtable const* get_vtable() {
static const variant_vtable table = make_vtable<T>();
return &table;
}
template<class T0, class...Ts>
struct my_variant {
std::size_t index = -1;
variant_vtable const* vtable = 0;
static constexpr auto data_size = max(sizeof(T0),sizeof(Ts)...);
static constexpr auto data_align = max(alignof(T0),alignof(Ts)...);
template<class T>
static constexpr std::size_t index_of() {
return index_of_in<T, T0, Ts...>::value;
}
typename std::aligned_storage< data_size, data_align >::type data;
template<class T>
T* get() {
if (index_of<T>() == index)
return static_cast<T*>((void*)&data);
else
return nullptr;
}
template<class T>
T const* get() const {
return const_cast<my_variant*>(this)->get<T>();
}
template<class F, class R>
using applicator = R(*)(F&&, my_variant*);
template<class T, class F, class R>
static applicator<F, R> get_applicator() {
return [](F&& f, my_variant* ptr)->R {
return std::forward<F>(f)( *ptr->get<T>() );
};
}
template<class F, class R=typename std::result_of<F(T0&)>::type>
R visit( F&& f ) & {
if (index == (std::size_t)-1) throw std::invalid_argument("variant");
static const applicator<F, R> table[] = {
get_applicator<T0, F, R>(),
get_applicator<Ts, F, R>()...
};
return table[index]( std::forward<F>(f), this );
}
template<class F,
class R=typename std::result_of<F(T0 const&)>::type
>
R visit( F&& f ) const& {
return const_cast<my_variant*>(this)->visit(
[&f](auto const& v)->R
{
return std::forward<F>(f)(v);
}
);
}
template<class F,
class R=typename std::result_of<F(T0&&)>::type
>
R visit( F&& f ) && {
return visit( [&f](auto& v)->R {
return std::forward<F>(f)(std::move(v));
} );
}
explicit operator bool() const { return vtable; }
template<class T, class...Args>
void emplace( Args&&...args ) {
clear();
::new( (void*)&data ) T(std::forward<Args>(args)...);
index = index_of<T>();
vtable = get_vtable<T>();
}
void clear() {
if (!vtable) return;
vtable->dtor( &data );
index = -1;
vtable = nullptr;
}
~my_variant() { clear(); }
my_variant() {}
void copy_from( my_variant const& o ) {
if (this == &o) return;
clear();
if (!o.vtable) return;
o.vtable->copy( &data, &o.data );
vtable = o.vtable;
index = o.index;
}
void move_from( my_variant&& o ) {
if (this == &o) return;
clear();
if (!o.vtable) return;
o.vtable->move( &data, &o.data );
vtable = o.vtable;
index = o.index;
}
my_variant( my_variant const& o ) {
copy_from(o);
}
my_variant( my_variant && o ) {
move_from(std::move(o));
}
my_variant& operator=(my_variant const& o) {
copy_from(o);
return *this;
}
my_variant& operator=(my_variant&& o) {
move_from(std::move(o));
return *this;
}
template<class T,
typename std::enable_if<!std::is_same<typename std::decay<T>::type, my_variant>{}, int>::type =0
>
my_variant( T&& t ) {
emplace<typename std::decay<T>::type>(std::forward<T>(t));
}
};
Live example.
Converting to C++11 will consist of a bunch of replacing lambdas with helpers. I don't like writing in C++11, and this C++14 is a mostly mechanical transformations away from it.
It is crude, in that visit takes exactly one variant and returns void, among other reasons.
Code is almost completely untested, but the design is sound.
There are two different use case. If the client program can know in advance the type of the value it wants, you can either use a different getter for each possible type (the good old C way with for example getInt, getDouble, getString), or use templated getters (modern C++ way):
template <class T>
T get(char *byte_array) {
T value;
# manage to extract the value
return T;
}
and explictely instanciate them to make sure that they will be available.
In the client library, the usage will be:
int i = get<int>(byte_array);
If the client program may received data in an order which is unknow at compile time, you must find a way to return a variant data type (old Basic programmers remember that). You can find implementations in boost or C++ 17, but a trivial implementation could be:
struct variant {
enum Type { INT, DOUBLE, STRING, ... } type;
union {
int int_val;
double d_val;
std::string str_val;
...
};
};
In that case the client program will use
variant v = get(byte_array);
switch v.type {
case INT:
...
}
I had this exact same problem with the HDF5 library. The type of a dataset from a file can be any native type (ignoring structs for now). My solution was the following:
Create an abstract base class
Create a template class that derives from the abstract class, where the type is the runtime type you need
Create static methods in the base class that will read the type from your system, and then decide what to instantiate.
For example:
static std::shared_ptr<Base> GetVariable()
{
switch(mytype)
{
case INT16:
return std::make_shared<Derived<uint16_t>>(value);
case INT32:
return std::make_shared<Derived<uint32_t>>(value);
//etc...
}
}
There are many advantages of this, including that you could make a base-class method that gets the string value for all your types, and use the cool std::to_string for all types. You'll only need specializations if you need to do something that is type specific.
You said you were working in C++11 so if you don't want to use Boost for it's Variant type then you can use a standard C-Style union if the return type is a limited set of types.
If you want a variable, unrestricted, return type then you will probably want to look into 'Concept Based Polymorphism' or 'Type Erasure' design patters.
It's also worth looking into 'Template Specialisation', it won't be any use unless you know the return type when calling but it's a good trick to get specific type handlers with the same signature.

Using std::variant with recursion, without using boost::recursive_wrapper

I'd like to replace boost::variants with C++17 std::variant and get rid of boost::recursive_wrapper, to remove dependency on boost completely in following code. How may I do that?
#include <boost/variant.hpp>
#include <type_traits>
using v = boost::variant<int, boost::recursive_wrapper<struct s> >;
struct s
{
v val;
};
template<template <typename...> class R, typename T, typename ... Ts>
auto reduce(T t, Ts ... /*ts*/)
{
return R<T, Ts...>{t};
}
template<typename T, typename F>
T adapt(F f)
{
static_assert(std::is_convertible_v<F, T>, "");
return f;
}
int main()
{
int val1 = 42;
s val2;
auto val3 = adapt<v>(reduce<boost::variant>(val1, val2));
}
There are two generic functions: first function reduce chooses at runtime which argument to return (here it just returns first argument for brevity), second function adapt converts a value of type F to a value of type T.
In this example reduce returns an object of type boost::variant<int, s> which is then converted to an object of type boost::variant<int, boost::recursive_wrapper<s> >.
boost::variant will heap allocate in order to have part of itself be recursively defined as itself. (It will also heap allocate in a number of other situations, uncertain how many)
std::variant will not. std::variant refuses to heap allocate.
There is no way to actually have a structure containing a possible variant of itself without a dynamic allocation, as such a structure can easily be shown to be infinite in size if statically declared. (You can encode the integer N by having N recursions of not-the-same: no fixed size buffer can hold an infinite amount of information.)
As such, the equivalent std::variant stores a smart pointer of some kind placeholder of a recursive instance of itself.
This may work:
struct s;
using v = std::variant< int, std::unique_ptr<s> >;
struct s
{
v val;
~s();
};
inline s::~s() = default;
and failing that, try:
struct destroy_s;
struct s;
using v = std::variant<int, std::unique_ptr<s, destroy_s> >;
struct s
{
v val;
~s();
};
struct destroy_s {
void operator()(s* ptr){ delete ptr; }
};
inline s::~s() = default;
It does mean that client code has to knowingly interact with the unique_ptr<s> and not the struct s directly.
If you want to support copy semantics, you'll have to write a value_ptr that does copies, and give it the equivalent of struct copy_s; to implement that copy.
template<class T>
struct default_copier {
// a copier must handle a null T const* in and return null:
T* operator()(T const* tin)const {
if (!tin) return nullptr;
return new T(*tin);
}
void operator()(void* dest, T const* tin)const {
if (!tin) return;
new(dest) T(*tin);
}
};
template<class T, class Copier=default_copier<T>, class Deleter=std::default_delete<T>,
class Base=std::unique_ptr<T, Deleter>
>
struct value_ptr:Base, private Copier {
using copier_type=Copier;
// also typedefs from unique_ptr
using Base::Base;
value_ptr( T const& t ):
Base( std::make_unique<T>(t) ),
Copier()
{}
value_ptr( T && t ):
Base( std::make_unique<T>(std::move(t)) ),
Copier()
{}
// almost-never-empty:
value_ptr():
Base( std::make_unique<T>() ),
Copier()
{}
value_ptr( Base b, Copier c={} ):
Base(std::move(b)),
Copier(std::move(c))
{}
Copier const& get_copier() const {
return *this;
}
value_ptr clone() const {
return {
Base(
get_copier()(this->get()),
this->get_deleter()
),
get_copier()
};
}
value_ptr(value_ptr&&)=default;
value_ptr& operator=(value_ptr&&)=default;
value_ptr(value_ptr const& o):value_ptr(o.clone()) {}
value_ptr& operator=(value_ptr const&o) {
if (o && *this) {
// if we are both non-null, assign contents:
**this = *o;
} else {
// otherwise, assign a clone (which could itself be null):
*this = o.clone();
}
return *this;
}
value_ptr& operator=( T const& t ) {
if (*this) {
**this = t;
} else {
*this = value_ptr(t);
}
return *this;
}
value_ptr& operator=( T && t ) {
if (*this) {
**this = std::move(t);
} else {
*this = value_ptr(std::move(t));
}
return *this;
}
T& get() { return **this; }
T const& get() const { return **this; }
T* get_pointer() {
if (!*this) return nullptr;
return std::addressof(get());
}
T const* get_pointer() const {
if (!*this) return nullptr;
return std::addressof(get());
}
// operator-> from unique_ptr
};
template<class T, class...Args>
value_ptr<T> make_value_ptr( Args&&... args ) {
return {std::make_unique<T>(std::forward<Args>(args)...)};
}
Live example of value_ptr.

How to properly create explicit argument-forwarding function with variadic templates in C++11

I'm working on a class that lets you dynamically register types with a common base type to keys, then dynamically construct instances of that type based on key. Here's what it looks like right now:
template<class Key, class Base>
class TypeRegistry
{
private:
FunctionRegistry<Key, Base*> m_registry;
template<class Derived>
static Base* make()
{
return new Derived();
}
public:
template<class Derived>
void register_type(const Key& key)
{
m_registry.register_function(key, &make<Derived>);
}
Base* make_type(const Key& key) const
{
auto maker = m_registry.get_function(key);
if(maker) return maker();
else return nullptr;
}
};
The FunctionRegistry class has this interface:
template<class Key, class Ret, class... Args>
class FunctionRegistry
{
public:
typedef Ret (*function_type)(Args...);
//register a key and function pointer
void register_function(const Key& key, function_type func);
//get a function pointer, or nullptr if the key is not registered
function_type get_function(const Key& key) const;
};
Now, my question is about extending TypeRegistry to support constructor arguments, using a variadic template. I don't know I should do the TypeRegistry::make function. Here's what I'm hoping for:
template<class Key, class Base, class... ConstructorArgs>
class TypeRegistry
{
private:
FunctionRegistry<Key, Base*, ConstructorArgs...> m_registry;
template<class Derived, ???>
static Base* make(???)
{
return new Derived(???);
}
public:
template<class Derived>
void register_type(const Key& key)
{
m_registry.register_function(key, &make<Derived, ???>);
}
template<class... DeterminedArgs>
Base* make_type(const Key& key, DeterminedArgs&&... args) const
{
auto maker = m_registry.get_function(key);
if(maker) return maker(std::forward<DeterminedArgs>(args)...);
else return nullptr;
}
};
The trouble is, I don't know how to properly template the make() function. Presumably it has to just be take ConstructorArgs... as its arguments, so that it can be properly registered in the FunctionRegistry, but then how do I make sure that all the arguments are properly forwarded (rvalue vs lvalue) to the Derived constructor?
Since you didn't put the definition of FunctionRegistry, I could not test it. Now I created the real example (which compiles) and where I fixed the issues. One of the biggest issue is that you tried to pass pointer to member function to a function pointer. For that reason, you must make the TypeRegistry::make a static method.
So, here is it :
#include <iostream>
#include <utility>
struct Abase
{
virtual ~Abase(){}
virtual void bar()=0;
};
struct A : Abase
{
A(int g,float h) : Abase(), a(g),b(h)
{
}
virtual ~A(){}
virtual void bar()
{
std::cout<<a<<b<<std::endl;
}
int a;float b;
};
Abase* foo(int&& v,float&& b)
{
return new A(v,b);
}
template<class Key, class Ret, class... Args>
class FunctionRegistry
{
public:
typedef Ret (*function_type)(Args...);
//register a key and function pointer
void register_function(const Key& key, function_type func)
{}
//get a function pointer, or nullptr if the key is not registered
function_type get_function(const Key& key) const
{
(void)key;
return foo;
}
};
template<class Key, class Base, class... ConstructorArgs>
class TypeRegistry
{
private:
FunctionRegistry<Key, Base*, ConstructorArgs&&...> m_registry;
template<class Derived>
static Base* make(ConstructorArgs&&... args)
{
return new Derived(std::forward<ConstructorArgs>(args)...);
}
public:
template<class Derived>
void register_type(const Key& key)
{
m_registry.register_function(key, &make<Derived> );
}
Base* make_type(const Key& key, ConstructorArgs&&... args) const
{
auto maker = m_registry.get_function(key);
if(maker) return maker(std::forward<ConstructorArgs>(args)...);
else return nullptr;
}
};
int main()
{
TypeRegistry< int, Abase, int, float > tr;
tr.register_type< A >( 5 );
auto a = tr.make_type( 5, 3, 5.3f );
a->bar();
}

How to signal expensive vs cheap template parameters?

I have working code for a simple bi_map, a bi-directional map class for storing associated key-value pairs in both directions. My current usage is, NID is some kind of numerical-id or enumeration, while OBJ is an expensive non-copyable class object.
Recently, I've noticed that I also have need for bi_map<NID,std::string>, std::string is a cheap OBJ that should really just be copied.
What is the right way to generalize the code below so that user can signal whether something is expensive (I want to use pointers/references) or cheap (I want to copy everything by value), so that I can use the proper implementation?
CODE
template<typename NID,typename OBJ>
class bi_map
{
std::map<NID,OBJ*> m_nid_2_ptr;
std::map<OBJ const*,NID> m_ptr_2_nid;
public:
void insert( NID nid, OBJ& obj )
{
m_nid_2_ptr.insert( std::make_pair( nid, &obj ));
m_ptr_2_nid.insert( std::make_pair( &obj, nid ));
}
NID operator[]( OBJ const& obj ) const
{
return m_ptr_2_nid.at( &obj );
}
OBJ const& operator[]( NID nid ) const
{
return *(m_nid_2_ptr.at( nid ));
}
using pairs_cb = std::function<void(NID,OBJ const&)>;
void pairs( pairs_cb cb ) const
{
for( const auto& p : m_nid_2_ptr )
cb( p.first, *p.second );
}
size_t size() const { return m_nid_2_ptr.size(); }
};
In general, there are multiple options and I guess, there is no one right answer. So, let's try to find something which works for you. You said you'd like to distinguish between cheap and expensive types. The most important design choice is the interface. You could use:
1) Specialize the template for pointers, having the explicit clue in the inteface that you are using a cheap type:
bi_map< int, std::string* > bi_map_1; // note * is to flag std::string as cheap
bi_map< int, ExpensiveObject > bi_map_2; // no *, thus using heavy implementation
which is implemented like this:
template< typename NID, typename OBJ >
struct bi_map
{
// implementation for expensive objects, use OBJ* or std::shared_ptr<OBJ>
};
// specialize of the second parameter is a pointer
template< typename NID, typename OBJ >
struct bi_map< NID, OBJ* >
{
// implementation for cheap objects, store a copy, i.e., use OBJ
};
of course you could also use & instead of * to flag the types if you find that more readable.
2) If you don't want the cheap/expensive separation to show up in the interface, i.e., if you want
bi_map< int, std::string > bi_map_1; // no *
bi_map< int, ExpensiveObject > bi_map_2; // no *
you need something different. One solution would be adding a defaulted template parameter:
template< typename >
struct is_expensive_for_bi_map : std::false_type {};
template< typename IND, typename OBJ, bool = is_expensive_for_bi_map< OBJ >::value >
struct bi_map
{
// implementation for expensive objects, use OBJ* or std::shared_ptr<OBJ>
};
template< typename NID, typename OBJ >
struct bi_map< NID, OBJ, false >
{
// implementation for cheap objects, store a copy, i.e., use OBJ
};
and for each type that you consider expensive, you add
template<>
struct is_expensive_for_bi_map< ExpensiveObject > : std::true_type {};
If expensive should be the default, just reverse the names and adapt the rest, should be easy enough.
Another option:
template<typename T>
struct notExpensive {
static const bool value = FALSE;
typedef T REF;
static T& ref(T& x) { return x; }
static T& deref(T& x) { return x; }
};
template<typename T>
struct isExpensive {
static const bool value = TRUE;
typedef T* REF;
static T* ref(T& x) { return &x; }
static T deref(T* x) { return x; }
};
template<typename T>
struct expensiveP : public notExpensive<T> {};
// List of expensive types:
template<> struct expensiveP<ExpensiveObject> : public isExpensive<T> {};
Then fill BiMap with expensiveP calls.

Using mem_fun_ref with a proxy object

I'm trying to use std::mem_fun_ref (Yes, the deprecated
version. Reasons below) to call a member function through a proxy.
template<typename T>
struct proxy {
T& operator*() { return *t; }
T* operator->() { return t; }
// no address of etc
T* t;
};
struct A {void foo() {}};
int main()
{
A a;
proxy<A> pa = {&a};
std::mem_fun_ref_t<void, A>
fn = std::mem_fun_ref(&A::foo);
fn(pa); // borks
return 0;
}
This works well with C++11 std::mem_fn but not boost::mem_fn, but
I can use neither of those, as I need to specify the type of the
binder in another place and the type of the resulting binder is
unspecified for boost::mem_fn. This wouldn't be a problem if I could
use decltype but I can't as the code needs to be compatible with
C++03.
What is the easiest way to work around this? A custom
mem_fun_through_proxy?
Edit: Another caveat is that the proxy class cannot be changed.
As Georg recommended, I implemented my own solution. Here is the short version:
// snipped solution: does not include const version and hack for void
// returns
#include <functional>
namespace mine {
template<typename Ret, typename T>
class mem_fun_ref_t : public std::unary_function<T, Ret>
{
public:
explicit
mem_fun_ref_t(Ret (T::*f)())
: f(f) { }
template<typename U>
Ret
operator()(U& u) const
{ return (*u.*f)(); }
Ret
operator()(T& t) const
{ return (t.*f)(); }
private:
Ret (T::*f)();
};
} // mine
template<typename T>
struct proxy {
T& operator*() { return *t; }
T* operator->() { return t; }
// no address of etc
T* t;
};
struct X {
int foo() {return 23;}
};
int main()
{
mine::mem_fun_ref_t<int, X> fn(&X::foo);
X x;
// normal
fn(x);
proxy<X> px = {&x};
fn(px);
return 0;
}