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.
Related
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.
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.
I am trying to create a templated wrapper class on stl unordered_map. I am passing the hash function class as a template parameter to the wrapper class and provided a string specialization. The below code compiles and works but if the commented part is included then compilation error saying:
"/usr/include/c++/6/bits/unordered_map.h:143:28: error: no matching
function for call to ‘HashFunction
::HashFunction()’
const hasher& __hf = hasher(),".
However, I am bound to have the ctor of the hash function class. I tried various ways but could not make it work. Please provide your thoughts/comments.
#include <iostream>
#include <unordered_map>
using namespace std;
template< class Key >
class HashFunction
{
public:
//HashFunction( const Key & inKey );
size_t operator()(const Key &inKey) const;
private:
unsigned mHashCode;
};
//template<>
//HashFunction< string >::HashFunction( const string & inKey )
//{
//mHashCode=std::hash<string>{}(inKey);
//}
template <>
size_t HashFunction< string >::operator()(const string &inKey) const
{
return std::hash<string>{}(inKey);
//return mHashCode;
}
template< class Key, class Val, class Hash = HashFunction< Key > >
class unordered_map_wrapper
{
public:
unordered_map_wrapper();
private:
unordered_map<Key, Val, Hash> * mTable;
};
template< class Key, class Val, class Hash >
unordered_map_wrapper< Key, Val, Hash >::unordered_map_wrapper()
{
mTable=new unordered_map<Key, Val, Hash>(10);
}
int main() {
unordered_map_wrapper<string, unsigned> h;
return 0;
}
This is not how the Hash template parameter is intended to work in std::unordered_map! The map creates one single Hash instance (using the default constructor, so you need to provide it!) which is used for all hash calculations needed further. So your class must look like this instead:
template<class Key>
class HashFunction
{
public:
// HashFunction(); <- can just leave it out...
size_t operator()(const Key& inKey) const;
};
template<>
size_t HashFunction<std::string>::operator()(const std::string& inKey) const
{
// calculate hash value in operator!!!
return std::hash<std::string>()(inKey);
}
To avoid constructing the std::hash all the time, though, I'd rather specialise the whole template class instead:
template<class Key>
class HashFunction; // leave entirely unimplemented
// (if it has no general meaning, at least...)
template<>
class HashFunction<std::string>
{
public:
size_t operator()(const std::string& inKey) const
{
return mHash(inKey);
}
private:
std::hash<std::string> mHash;
};
It does not make much sense re-implementing something that is already there, though. May I assume that you used std::string here just as a place holder for your own class?
By the way: A simple typedef would do the job easier than your wrapper class:
template <typename Key, typename Value>
using my_unordered_map = std::unordered_map<Key, Value, HashFunction<Key>>;
Maybe you are interested in alternatives, too? Lets first assume you have two classes (instead of std::string):
class C1
{ };
class C2
{ };
Most elegant solution (in my eyes at least) is simply specialising std::hash for your classes (while in general, it is illegal to add something to std namespace, template specialisations are the exception...):
namespace std
{
template<>
class hash<C1>
{
public:
size_t operator()(C const& c) const
{
return 0; // your implementation here...
}
};
// same for C2
}
// no typedef necessary, just use std::unordered_map directly:
std::unordered_map<C1, unsigned> m1;
std::unordered_map<C2, unsigned> m2;
You can provide your own HashFunction class, providing overloads:
class HashFunction
{
public:
size_t operator()(C1 const& c) const
{
return 0;
}
size_t operator()(C2 const& c) const
{
return 0;
}
};
Again, a typedef makes your life easier:
template <typename Key, typename Value>
using my_unordered_map = std::unordered_map<Key, Value, HashFunction>;
std::unordered_map<C1, unsigned, HashFunction> m1;
my_unordered_map<C1, unsigned> m1_;
std::unordered_map<C2, unsigned, HashFunction> m2;
my_unordered_map<C2, unsigned> m2_;
Finally, if you absolutely need to initialise your HashFunction with some parameters to configure it correctly, you can do so, but you have to deliver a pre-configured instance to your hash map then!
template<typename T>
class HashFunction
{
public:
HashFunction(double value);
size_t operator()(T const& c) const;
private:
double data;
};
template<typename T>
HashFunction<T>::HashFunction(double value)
: data(value)
{ }
template<>
size_t HashFunction<C1>::operator()(C1 const& c) const
{
return static_cast<size_t>(data);
};
template<>
size_t HashFunction<C2>::operator()(C2 const& c) const
{
return static_cast<size_t>(data);
};
template <typename Key, typename Value>
using my_unordered_map = std::unordered_map<Key, Value, HashFunction<Key>>;
my_unordered_map<C1, unsigned> m1(12, HashFunction<C1>(10.12));
my_unordered_map<C2, unsigned> m2(10, HashFunction<C2>(12.10));
Well, now, at least, your wrapper class can come in handy again:
template <typename Key, typename Value, typename Hash = HashFunction<Key>>
class unordered_map_wrapper
{
public:
unordered_map_wrapper()
: mMap(16, Hash())
{ }
unordered_map_wrapper(double parameter)
: mMap(16, Hash(parameter))
{ }
private:
std::unordered_map<Key, Value, Hash> mMap;
};
unordered_map_wrapper<C1, unsigned> m1(10.12);
unordered_map_wrapper<C2, unsigned> m2(12.10);
// possible due to provided default ctor:
unordered_map_wrapper<std::string, unsigned, std::hash<std::string>> m3;
It expects to have a default constructor, which is removed when you define your custom version.
This compiles:
template< class Key >
class HashFunction
{
public:
HashFunction(){};
HashFunction( const Key & inKey );
size_t operator()(const Key &inKey) const;
private:
unsigned mHashCode;
};
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.
BACKGROUND
I am trying to write a class template Hasher which will be implemented in two different ways depending on whether or not std::hash<T> has been implemented for T:
template<typename T>
struct Hasher
{
std::size_t hash( T t ) const;
// implement as A { std::hash<T> h; return h( t ); }
// or B { std::hash<std::string> h; return h( t.to_string() ); }
};
If std::hash<T> has been specialised, I want to use it. If not, I expect T to have a to_string() function to return a key for me to hash on.
For example, according to cppreference, if T is long long, a pointer, or std::string, I want version A. If it is not one of those standard ones listed and if the user has not specialised std::hash<T> for his own type, I expect T to have a std::string to_string() const for me to call. In this case, I want to generate version B.
PROBLEM
How do I use C++11/type_traits/no-SFINAE to generate the proper implementation?
ADDENDUM
Another way to think about it:
It's almost like I want version B to be the default behavior (ie, if no specialization exists, to use version B).
TESTED NAWAZ'S SOLUTION
I just tried out Nawaz's solution on gcc 4.8.1 as his came in first and is actually the easiest for me to read and understand (more important).
#include <functional>
#include <cassert>
template<typename T>
class Hasher
{
// overloading rules will select this one first... ...unless it's not valid
template<typename U>
static auto hash_impl(U const& u, int)
-> decltype(std::hash<U>().operator()( u ))
{
return std::hash<U>().operator()( u );
}
// as a fallback, we will pick this one
template<typename U>
static auto hash_impl(U const& u, ... )
-> std::size_t
{
return std::hash<std::string>().operator()(u.to_string());
}
public:
auto hash( T t ) const -> decltype( hash_impl(t,0) )
{
return hash_impl( t, 0 );
}
};
struct Foo
{
std::string m_id;
std::string to_string() const { return m_id; }
};
int
main( int argc, char** argv )
{
std::string s{ "Bar" };
Foo f{ s };
long long l{ 42ll };
Hasher<long long> hl;
Hasher<Foo> hf;
Hasher<std::string> hs;
assert( hl.hash( l )==l );
assert( hf.hash( f )==hs.hash( s ));
return 0;
}
TESTED DANIEL FREY'S SOLUTION
Daniel's implementation is also very interesting. By computing first whether or not we have a hash, I am able to use tag-dispatch to select the implementation I want. We have a nice pattern/separation-of-concerns which leads to very clean code.
However, in the implementation of has_hash<>, the arguments to decltype confused me at first. In fact, it shouldn't read as arguments. Rather, it is a list of expressions (comma separated expressions). We need to follow the rules as expressed here.
C++ ensures that each of the expressions is evaluated and its side
effects take place. However, the value of an entire comma-separated
expression is only the result of the rightmost expression.
Also, the use of void() was a mystery to me at first. When I changed it to double() to see what would happen, it was clear why it really should be void() (so we don't need to pass in that second template parameter).
#include <functional>
#include <cassert>
template< typename, typename = void >
struct has_hash
: std::false_type {};
template< typename T >
struct has_hash< T, decltype( std::hash< T >()( std::declval< T >() ), void() ) >
: std::true_type {};
template<typename T>
class Hasher
{
static std::size_t hash_impl(T const& t, std::true_type::type )
{
return std::hash<T>().operator()( t );
}
static std::size_t hash_impl(T const& t, std::false_type::type )
{
return std::hash<std::string>().operator()(t.to_string());
}
public:
std::size_t hash( T t ) const
{
return hash_impl( t, typename has_hash<T>::type() );
}
};
struct Foo
{
std::string m_id;
std::string to_string() const { return m_id; }
};
int
main( int argc, char** argv )
{
std::string s{ "Bar" };
Foo f{ s };
long long l{ 42ll };
Hasher<long long> hl;
Hasher<Foo> hf;
Hasher<std::string> hs;
assert( hl.hash( l )==l );
assert( hf.hash( f )==hs.hash( s ));
return 0;
}
You could use Expression SFINAE introduced by C++11.
Here is one example how it is implemented:
template<typename T>
struct Hasher
{
auto hash( T t ) const -> decltype(hash_impl(t,0))
{
return hash_impl(t, 0);
}
private:
template<typename U>
static auto hash_impl(U const & u, int) -> decltype(std::hash<U>().hash(u))
{
return std::hash<U>().hash(u);
}
template<typename U>
static auto hash_impl(U const & u, ... ) -> std::string
{
return u.to_string();
}
};
Note that hash_impl is an overloaded function template. So when you write this:
return hash_impl(t, 0);
Since the second argument 0 is int, the above first attempts to invoke hash_impl which uses std::hash — this attempt might fail if std::hash<U>().hash(u) is not a valid expression (Expression SFINAE). If that fails, then the second hash_impl is invoked.
You could just test if std::hash<T>()(...) can be called with type in question. If so, you'll get back a type from decltype() which can be used in a SFINAE expression to determine the size of a return type:
template <typename T>
struct has_hash
{
template <typename S>
static char (&test(S*, decltype(std::hash<S>()(std::declval<T&>()))* = 0))[1];
static char (&test(...))[2];
static constexpr bool value = 1 == sizeof(test(static_cast<T*>(0)));
};
Base on this you could then use the has_hash<T>::value to determine if there is a usable hash function already defined.
If you need to test if an expression is valid or not, I prefer the following implementation:
template< typename, typename = void >
struct has_hash
: std::false_type {};
template< typename T >
struct has_hash< T, decltype( std::hash< T >()( std::declval< T >() ), void() ) >
// ^^ expression here ------------------^^
: std::true_type {};
Live example
Yet another implementation
First, some boilerplate. type_sink and TypeSink let us evaluate types, and discard them.
template<typename... T> struct type_sink {typedef void type;};
template<typename... T> using TypeSink = typename type_sink<T>::type;
We then write a really simple has_hash that uses SFINAE. The default choice is "no hash", and the specialization is valid iff std::hash<T>()( t ) is a valid expression for a variable t of type T:
template<typename T, typename=void> struct has_hash:std::false_type {};
template<typename T> struct has_hash<
T, TypeSink< decltype( std::hash<T>()( std::declval<T&>() ) ) >
>: std::true_type {};
we then write our universal hasher:
template<typename T>
struct Hasher
{
private:
typedef has_hash< typename std::decay<T>::type > test_for_hash;
public:
std::size_t operator()( T t ) const {
return hash( std::forward<T>(t), test_for_hash() );
}
private:
std::size_t hash( T t, std::true_type has_hash ) const {
return std::hash<T>()( std::forward<T>(t) );
}
std::size_t hash( T t, std::false_type no_hash ) const {
// TODO: static_assert that t.to_string exists, and if not give a useful error message
return std::hash<std::string>()( std::forward<T>(t).to_string() )
}
};
where we use the has_hash trait to do tagged dispatching to either the "use hash directly" or "to_string then hash".
We can do more layers of this dispatching.
I took the liberty of making it somewhat move-aware, in that T can be T& or T const& or T and it behaves reasonably. (I don't know about T&& off the top of my head).
As noted in other comments, some work to generate better error messages can be done. We want the compiler's error message to complain about the lack of a hash<T> implementation rather than a to_string implementation probably. That would involve writing a has_to_string traits class and either doing another layer of tag dispatching, or doing a static_assert to generate a useful message telling the end user to implement either the hash<T> specialization or T::to_string.
Another option would be to make a universal hasher:
template<typename T>
struct Hasher
{
private:
typedef has_hash< T > test_for_hash;
public:
template<typename U>
std::size_t operator()( U&& u ) const {
return hash( std::forward<U>(u), test_for_hash() );
}
private:
template<typename U>
std::size_t hash( U&& u, std::true_type has_hash ) const {
return std::hash<T>()( std::forward<U>(u) ); // conversion occurs here
}
template<typename U>
std::size_t hash( U&& u, std::false_type no_hash ) const {
// TODO: static_assert that t.to_string exists, and if not give a useful error message
T t = std::forward<U>(u); // conversion occurs here -- note, implicit on purpose!
return std::hash<std::string>()( std::move(t).to_string() )
}
};
which defers transformation-to-T until the last moment.