Turning a private struct hasher operator into static - c++

I have implemented a class A which holds an unordered_set of class B instances, using a custom hasher function.
File a.hh:
#include "b.hh"
class A {
private:
struct HashB_ {
size_t operator()( const B & ) const ;
};
typedef std::unordered_set< B, A::HashB_ > HashTable_t_ ;
HashTable_t_ hash_table_;
};
File a.cpp:
#include "a.hh"
size_t
A::HashB_::operator()( const B & b ) const {
return b.getHash();
}
Where b.getHash() implements the actual hashing.
My goal is to make this private hasher function static, if possible, as it does not interact at all with the members of class A. Defining the hasher outside of class A would be an alternative, but I wish to hide the implementation outside of class A.
If I try to declare static size_t operator()( const B & ); I get the following compilation error: must be a nonstatic member function.
And if I declare static struct HashB_ I get the following error: a storage class can only be specified for objects and functions.
Is it possible do turn this private hasher into a private "static" hasher? And would it make any sense in doing so? Or should I do it with a friend hasher, instead, to hide the implementation?

The function call operator does require an object to work on even if they don't need to touch the object. That's a deliberate choice to establish the relevant context for looking up the function call operator. That operator can't be static.
You could use a static function in your class A. However, the unordered containers use an object to specify the hashing operation. A function pointer to the static member is a suitable object. However, you'd need to use a function pointer type for the hasher template argument and pass the function pointer to the constructor of the unordered cintainer. Aside to this syntactic complication this approach probably has a negative performance impact: conpilers are really good at inlining member functions which do not touch any if the member. They do have a hard time doing the appropriate analysis with function pointers, even in simple looking cases.
tl;dr: don't worry about the hash object not having any member and the function call operator being non-static: it is likely the most effective approach!

Related

Map of function pointers to member functions

I've tried various solutions on SO to solve this problem, yet I must be doing something wrong.
I have several classes where methods in each of the classes have the same method signature:
typedef int (*ControllerMethod)(const std::string &data, const std::unordered_map<std::string, std::string> &params);
And an example class having some method using that signature:
class StaticContentController {
public:
int handleStaticContentRequest(const std::string &data, const std::unordered_map<std::string, std::string> &params) {
return 1;
}
}
Now I try to create a map of pointers to member functions:
std::map<std::string, ControllerMethod> operations;
operations.emplace("staticContent", &StaticContentController::handleStaticContentRequest);
std::string d("test.txt");
ControllerMethod f = operations["staticContent"];
auto s = ((_staticContentController).*f)(d, pooledQueries); // <- compile error here
but calling the method gives the compile error
Right hand operand to .* has non-pointer-to-member type 'web::server::ControllerMethod'
What am I missing?
Update:
I now have an empty Controller base class which other controller classes inherit from:
namespace web { namespace server {
class Controller {
};
typedef ControllerResponse (Controller::*ControllerMethod)(const std::string &data, const std::unordered_map<std::string, std::string> &params);
}}
Now I'm getting the following error at operations.emplace():
No matching constructor for initialization of 'std::__1::pair<const std::__1::basic_string<char>, web::server::ControllerResponse
Updated answer
You're trying to use two different paradigms here, and they aren't really compatible with one another. If I interpret your edit correctly, you're trying to create a map of functions that call into other classes, and you want to declare this map as a set of function pointers.
Function pointers are an assembly level construct, exposed by C. The syntax reflects this - and getting a C++ class to conform to this is not possible without help - namely, adding a context pointer parameter that is associated with every function pointer, and converting the context pointer to a class instance to call the member function.
So, how do we fix the problem?
In both of the next approaches, we need a context object associated with the function table. This involves creating a structure to hold the member function and the context:
template<typename T> struct FunctionTableEntry
{
ControllerMethod Function;
T* Context;
};
and our function pointer becomes the following:
typedef ControllerResponse (T::*ControllerMethod)(const std::string &data, const StringMap &params);
Here, StringMap is a typedef for std::unordered_map<std::string, std::string>.
Our main problem now comes with removing the template parameter T, as we can't make maps of runtime defined templates (a template who's type will only be known at run time).
There are two main approaches to take in resolving this, and both have issues that will need to be considered. The first is to perform C style type erasure with pointers and very careful association. The second is to abandon function pointers in favor of C++ function objects.
C-Style Type Erasure
This option involves using C-style casts to convert the class instance pointer to its base class type, the member function pointer to the type expected by the function declaration, and then making the call as though the base class defines the method. This requires the use of pointers, and cannot be done without them.
To do this, our FunctionTableEntry structure changes to the following:
struct FunctionTableEntry
{
ControllerMethod Function;
Controller* Context;
}
and our function pointer to:
typedef ControllerResponse (Controller::*ControllerMethod)(const std::string &data, const StringMap &params);
To add a new entry, we do the following:
std::map<std::string, FunctionTableEntry> operations;
FunctionTableEntry Entry;
Entry.Function = (ControllerMethod)&StaticContentController::handleStaticContentRequest;
Entry.Context = (Controller*)&_staticContentController;
operations.emplace("staticContent", Entry);
And to call it:
FunctionTableEntry f = operations["staticContent"];
auto s = ((f.Context)->*f.Function)(d, pooledQueries);
This method suffers from a few drawbacks - first, you have no other choice but to use pointers to refer to your controller objects - casting will not function properly otherwise. You can make this a bit more C++ friendly with std::shared_ptr, but otherwise, there is no way to replace it. This also means you need to carefully manage the lifetime of your controller objects. If they get freed while the function table is still referencing them you will almost certainly crash the system.
Second, the casting can cause issues with complex inheritance hierarchies. This method only works if (Controller*)_staticContentController == _staticContentController, i.e. casting to the base class gives the same numerical pointer value. Otherwise, the called method will fail as it will not be able to properly reference its local data.
This method has the advantage of being quite fast, however. There is no function overhead besides the table lookup, and the generated assembly is not much more than just calling the function normally. It is also runtime independent - so long as the equality expression above is true with all users of the controller system, anyone with a C++ compiler can create a new controller and this system will be able to call their functions, even if they use a completely different runtime library.
Additionally, if you know the controller instance is going to be used with multiple functions, you can modify the structure to provide a map of functions associated with one Context value, allowing you to reduce some of the memory overhead. This may not be possible with your design, but it's worth looking into if memory is a concern.
C++ Function Objects
The second solution is to completely do away with C-style function pointers altogether and use std::function. Since std::function can contain instance data as part of itself, and can be placed into a map, this allows you to std::bind a member function, creating a partially specified function call (I believe in functional programming this is what's called a closure).
In this case, there is no FunctionTableEntry structure - instead we use the following:
typedef std::function<ControllerResponse(const std::string&, const StringMap&)> ControllerMethod;
To add a new method, we do the following:
std::map<std::string, ControllerMethod> operations;
operations.emplace("staticContent", std::bind(&StaticContextController::handleStaticContentRequest, &_staticContentController, std::placeholders::_1, std::placeholders::_2);
This creates a closure that calls the member function with the required controller instance.
To call this, we do the following:
std::string d("test.txt");
ControllerMethod f = operations["staticContent"];
auto s = f(d, pooledQueries);
C++ function objects override operator (), which allows them to work as though they were static functions.
This method allows for both member functions and static functions to exist in the same map. It also allows for complex inheritance hierarchies to occur, as there is no casting to make things function - everything occurs with template functions.
The downside to this method is you still need to deal with object lifespan - the content controller objects cannot be destroyed until after the function map has been cleared. In addition, there is some overhead due to the use of std::function with placeholder parameters (though that likely depends on the runtime library in use, my tests have shown it generates a whole lot more code in x86-64 GCC 9.3).
This method also is not runtime independent - whatever runtime you choose to use here must also be used by every programmer that uses this code, otherwise incompatibilities in the way each library creates and stores std::function will cause strange failures. This means no compiler mixing - if you used MSVC 2019 to build the API, everyone else who uses this library must use MSVC2019 to build their controller component. If you aren't providing an API here, then this is not an issue.
Original answer
Your function pointer declaration is wrong - pointers to members have a different syntax to the normal function pointer typedef.
A normal function pointer uses the syntax you have currently:
typedef int (*foo)(int x, int y);
A pointer to member function typedef looks like this:
typedef int (SomeClass::*foo)(int x, int y);
The SomeClass:: section is required as pointers to members have an additional parameter to them, called this. In C++, the this pointer is passed as the first argument to the function, which makes the function declaration different (as the actual assembly code needed to call the function is different, see MSVC generated assembly for a real world example).
To solve the issue, you need to provide a base class that can be used to declare the typedef, then inherit from that class to allow the method to be called. This is effectively identical to using inheritance, unless you have multiple methods in the same type that have the same signature, but do different things.
The DirectX 11 Effects framework uses this exact paradigm to avoid branching when configuring different shader types in the graphics pipeline - see here, at line 590.
As pointed out, the type of a non-static member function of the class StaticContentController is not:
typedef int (*ControllerMethod)(const std::string &data, const std::unordered_map<std::string, std::string> &params);
Instead, it is:
typedef int (StaticContentController::*StaticContentControllerMethod)(const std::string &data, const std::unordered_map<std::string, std::string> &params);
This was your initial error.
This makes sense as you need an instance to call the member function, and the instance has a type as well. And it makes sense that if you have a Base::*Function pointer, you can call it with an instance of a class publicly and unambiguously derived from Base, because a derived pointer can be converted implicitly to a base pointer.
It also makes sense that you cannot assign a Derived::*Function pointer to a Base::*Function pointer because the result could be called with any Base instance, which need not be a Derived instance. This was the error in the question update.
In this very limited circumstance, C++ behaves completely logically.
With the modification to the correct type, your snippet will compile:
std::map<std::string, StaticContentControllerMethod> operations;
operations.emplace("staticContent",
&StaticContentController::handleStaticContentRequest);
std::string d("test.txt");
StaticContentControllerMethod f = operations["staticContent"];
auto s = ((_staticContentController).*f)(d, pooledQueries); // <- works
So presumably your actual question is how to store in this map member function pointers for multiple classes and not just StaticContentController. But that is the wrong question. You have to have the instance (_staticContentController) to invoke the member function pointer, so you already know the type.
So maybe you want to ask how to erase the type. One way is storing something that doesn't require an instance: for that, use std::function as the mapped type and bind the instance when inserting into the map. That would work and be straightforward if you have the controller at the time the map is created. A second way is using a type erasing type like std::any for the mapped type, and use any_cast at the point of use to return it to its initial type. A third way is to use a common base class with virtual functions which are overridden in your classes. Since the virtual functions can be called with a base pointer, you can store member function pointers of the base class.
Alternatively, maybe you want to ask how to have a type-indexed collection: the type is known at lookup time (because you have an instance) and you need to lookup a value whose type (member function pointer) depends on the "key" type.
The simplest way to do this is to have templated classes, and let the compiler handle the mapping:
template<typename T>
struct operations {
static std::map<std::string, void (T::*)(etc.)> pointers;
};
// use:
operations<StaticContentController>::pointers["staticContent"];
Another version of type-indexing might have the following interface:
template<template<typename> typename Value>
class type_keyed_map
{
public:
template<typename T>
void insert(std::unique_ptr<Value<T>> value);
template<typename T>
auto find() -> Value<T>*; // return null if not found
};
You can use a std::map in the implementation, but std::map does not allow multiple value types.

Static const global functor instances

What is the best way to declare global instances of a function object so I can import and use the instances as callables throughout my program?
Specifically, I have created a template class which serves as a custom deleter for a shared pointer. Several pointer types in a third party library need to be deleted with a "Free" function that takes a reference to the pointer. An instance of the class is instantiated with the type of the pointer to delete, and a pointer to a function with the signature of the Free function. I am declaring the instances as const because there is no need for the member function pointer to ever change.
template <class T>
class Deleter {
public:
typedef typename bool(CALLING_CONVENTION *DeleterFunc)(T**);
Deleter(DeleterFunc deleter) : deleter_(deleter) {}
void operator() (T* t) { if (t) { deleter_(&t) }
private:
DeleterFunc deleter_;
};
static const Deleter<I_x> x_deleter(FreeXInterface);
My first attempt was a create instances for each of the pointer types in the .h file, but this resulted in multiply defined symbols if I include this header file in other code. So I changed the declaration of the instances to "static" and this compiles and seems to work fine, but I have seen warnings that this is not a good idea (especially if the objects belong to a namespace) because static is causing the linkage to be file-only, and that each compilation unit will have its own copy.
My question is does this matter if I don't really care if they are the same instance between files? I am not using this as global data, and the function objects don't really have any state. Would I have any concerns about threading if these objects are declared static? Is there a better way to implement this without using the static keyword?
Well, the basic answer to your linker question is here: How do I use extern to share variables between source files? Let's try to do a little better, though: You currently have to refer to the deletion function every time you instantiate a function, instead of having it chosen automatically based on the type.
Of course we often pick types based on types: std::vector<int> is the dynamic array which is capable of holding ints. Linkage isn't a huge problem there: Everything's more or less inlined, each translation unit which mentions std::vector<int>::push_back() gets its own copy of the object code to put an int into a vector of ints, and the linker (sometimes) helps out by removing duplicated instantiations. But here we want an object, not a type.
So what's halfway between templates and global objects? Static members of templated classes! Check it:
// Deleter.h
typedef typename bool(CALLING_CONVENTION *DeleterFunc)(T**);
template <class T>
class Deleter {
public:
static DeleterFunc s_deleterFunc;
void operator() (T* t) {
if(t) { s_deleterFunc(&t); }
}
};
// XDeleter.cpp
#include "Deleter.h"
template<>
DeleterFunc Deleter<I_x>::s_deleterFunc = FreeXInterface;
// YDeleter.cpp
#include "Deleter.h"
template<>
DeleterFunc Deleter<I_y>::s_deleterFunc = FreeYInterface;
For each type you want a deleter for, you just provide the instantiation of the static member for the specialized class. The code which calls Deleter<I_x>::operator() only needs to include Deleter.h; the linker will take care of matching it to the one declared in XDeleter.cpp.
Note that I'm doing it with templated classes, rather than templated functions, only because it allows you to use your function pointers. But you could instead do something as simple as:
// Deleter.h
template <class T>
invokeDeleter(T* t);
// XDeleter.cpp
#include "Deleter.h"
template<>
invokeDeleter<I_x>(I_x* x)
{
...
}
// YDeleter.cpp
#include "Deleter.h"
template<>
invokeDeleter<I_y>(I_y* y)
{
...
}

How to use std::function when implementing a HashMap in C++

I am working on HashMap class with typedef std::function in HashMap class declaration.
typedef std::function<unsigned int(const std::string&)> HashFunction;
For private member of the class, I have HashFunction hash that can be used with my own hash function or use other function supplied to constructor.
HashFunction hash;
unsigned int myHashFunction(const std::string&) const;
A default constructor must set the hash to default value which in my case is myHashFunction. And a constructor which a HashFunction as parameter must use that particular function, not myHashFunction.
HashMap::HashMap()
: map(new Node*[INITIAL_BUCKET_COUNT]), mapSize(0), mapCapacity(INITIAL_BUCKET_COUNT),
hash(std::bind(&HashMap::myHashFunction, this)) // This is definitely not correct
{
initializeMap();
}
HashMap::HashMap(HashFunction hashFunction)
: map(new Node*[INITIAL_BUCKET_COUNT]), mapSize(0), mapCapacity(INITIAL_BUCKET_COUNT),
hash(hashFunction) //Is this correct?
{
initializeMap();
}
How can I bind myHashFunction or a supplied hash function to hash, so that I can use hash(key) in the class member functions to support both hash functions? Please direct me to the right path if I am completely getting it wrong. Thanks.
For the std::bind line, if you're trying to bind a member function then you need to include a placeholder, like so:
std::bind(&HashMap::myHashFunction, this, std::placeholders::_1);
You might find it better to make myHashFunction a static member function though, unless it actually uses other members or data in your HashMap (my guess is it probably shouldn't).
Why don't you use std::hash? It's defined in the <functional> header.

implementing a factory that registers non-static member functions to it in C++

I have a C++ singleton factory-like class called MemMgr which is in charge of managing heap memory for objects in a library:
#include <vector>
class MemMgr
{
public:
// Callback interface of functions to register with MemMgr
typedef size_t (*MemSizeFunc)(void);
void Register(MemSizeFunc memSizeFunc);
static MemMgr & GetInst(void);
// more public functionality related to managing memory
private:
// a vector (not a map) of functions pointers to keep track of
std::vector<MemSizeFunc> m_memSizeFuncs;
MemMgr(void);
MemMgr(MemMgr const &);
MemMgr & operator= (MemMgr const &);
// more private functionality related to managing memory
};
What I'd like to be able to do is to have objects of any classes that would like to utilize managed memory be able to register themselves with MemMgr via a (non-static) member function which will calculate and return the amount of managed memory that that particular object needs. Something like the following:
class MemMgrUser
{
public:
MemMgrUser(void)
{
MemMgr::GetInst().Register(GetManagedMemSize);
}
private:
size_t GetManagedMemSize(void)
{
// calculations involving member variables
}
};
(Then, prior to MemMgr actually allocating any memory, it would query the size-related functions registered to it in order to find out the amount of memory to allocate.)
However, the compiler yells at me when I try the above approach b/c I am trying to register member function pointers, not plain-vanilla function pointers.
Does anyone have any suggestions on how I could implement such functionality? I am having problems seeing how a template implementation (or polymorphic one) would be implemented.
Thank you,
Aaron
You don't even try to register a member function pointer. That would have to be specified as &MemMgrUser::GetManagedMemSize. You can't use the plain name of a member function, except in an expression that calls it.
But even if you had a member function pointer, it cannot be used in the same way as a plain function pointer of the same apparent signature. Calling a member function always requires an object to call it on. The this pointer available in the function is an additional, hidden parameter.
If you can use features of the C++11 standard library, you could typedef std::function<size_t (void)> MemSizeFunc; instead of the current typedef. That allows you to store various kinds of functions and function objects that are callable with that signature as a MemSizeFunc. In particular you could register your GetManagedMemSize member function bound to a suitable MemMgrUser object, for example as:
MemMgrUser()
{
MemMgr::GetInst().Register(std::bind(&MemMgrUser::GetManagedMemSize, *this));
}

How to use a non-static member function in Hasher?

I need to establish a hash table using a hasher different from the default one, so I write something like:
class foo {
public:
...
private:
struct myhasher {
size_t operator() (myclass bar) { return hash_calculation bar; }
}
static size_t hash_calculation (myclass bar) {
// do some calculation
}
hash_map<myclass, myhasher> myhashmap;
}
It works. Now for some reason I have to write a non-static member function to replace hash_calculation, say, it needs a non-static member of the class as an argument. Then the whole thing failed because I cannot use a non-static method in a nested struct.
This is somehow similar to another widely discussed problem: how to use a non-static function to do comparison or sorting. See for example:
Using a non-static class member inside a comparison function
and
C++ std list sort with custom comparator that depends on an member variable for the object instance . They both established a functor instead of a function as the comparator. However in my case this trick does not work because I need a class name inside the hash_map definition, not a specific struct object. What should I do? Thanks in advance for your help!
You can't. How is the hash_map supposed to know which instance of myhasher should be used when calling myhaser::hash_calculation?
hash_map isn't part of the standard C++ library, not even in C++11, so it's a custom class, and you have included no information about how it works. If there is a way for it to take some sort of constructor argument for which myhasher it should use, you're in luck. But it doesn't sound like it.
Also, you're using pass by value when you probably mean to pass in a const reference. Passing by value is likely going to be really slow and inefficient.
The standard "hash-map", i.e., std::unordered_map<K, V, H, E, A> takes a hash object of type H as constructor argument. A copy of this object is used to determine the hash for the object by way of the function call operator. This way can provide some context. Obviously, you were already using a non-static function call operator but you choose to delegate to a static member.