I am attempting to write a function which will operate on a std::map of any key and class pointer given to it, and create a new std::map with an index based on the return value of a function in the class. Essentially, a template function to re-index a map based on a function in its contained class. However, I am having compiler errors when trying to invoke the function.
template<class AnyType, class ValueType, class FunctionType>
AssocArray<FunctionType,ValueType> reindex( const AssocArray<AnyType, ValueType>& original, FunctionType (*getterFunction)() ) {
AssocArray<FunctionType, ValueType> ret;
FunctionType index;
for(typename AssocArray<AnyType,ValueType>::const_iterator it = original.begin(); it!=original.end(); it++) {
index = ((*it->second).*getterFunction)();
ret[index] = it->second;
}
return ret;
}
Invoked by:
floatIndexed = reindex( intIndexed, &test::getB );
Where getB is of float type.
This results in the compiler error:
src/World.cpp:78:50: error: no matching function for call to ‘reindex(std::map<int, onathacar::test*>&, float (onathacar::test::*)())’
src/World.cpp:78:50: note: candidate is:
./include/Types.h:123:36: note: template<class AnyType, class ValueType, class FunctionType> std::map<PreservedType, ValueType> onathacar::reindex(const std::map<LookupType, ValueType>&, FunctionType (*)())
I have tried different variations of this, including using "FunctionType (ValueType::*getterFunction)()" and changing "AssocArray" to "AssocArray". The only one which worked added a fourth template argument:
template<class AnyType, class ValueType, class FunctionType, class SomeType>
AssocArray<FunctionType,ValueType> reindex( const AssocArray<AnyType, ValueType>& original, FunctionType (SomeType::*getterFunction)() ) {
However, this seems like it would potentially allow functions that are not actually members of ValueType to be called, and so I would prefer some other option. I am not even sure what is wrong, as it appears the templates match, at least with the addition of "ValueType::". Why does the call not match the template, and is there a way to fix it without a fourth templated type?
For more context, Header Containing Implementation and Calling Function.
You have two problems. The first is that reindex implies that the value types are values, but you use them as pointers:
AssocArray<float, test*> floatIndexed;
floatIndexed = reindex( intIndexed, &test::getB );
The second is that reindex's second parameter needs to be declared as a member function, not a free function. So reindex should look like this:
template<class AnyType, class ValueType, class FunctionType>
AssocArray<FunctionType,ValueType *> reindex( const AssocArray<AnyType, ValueType *>& original, FunctionType (ValueType:: *getterFunction)() ) {
AssocArray<FunctionType, ValueType*> ret;
FunctionType index;
for(typename AssocArray<AnyType,ValueType*>::const_iterator it = original.begin(); it!=original.end(); it++) {
index = ((*it->second)->*getterFunction)();
ret[index] = it->second;
}
return ret;
}
It seems that you are trying to use your rindex() function with members but your function is declared to use non-members. This won't work. The reason this won't work is that the you need an object to access either function or data members of a class.
template<class A, class B>
class X{
public:
};
class Y{
public:
int func() { return 42; }
};
template<class A, class B, class C>
X<C,B> reindex( const X<A, B>& original, C (B::*getterFunction)() ) {
X<C, B> x2;
cout << "hello" << endl;
return x2;
}
int main() {
X x1;
reindex(x1,&Y::func);
return 0;
}
This works and gives perfectly valid results.
The problem with your call AssocArray intIndexed, is the fact that you are trying to pass &test::getB as the getter function, which assumes valueType = test, where as your actual value type, is test*.
Related
I have a hash table class. It has a template parameter hashFunction:
#include <string>
template<class KeyType> using hashFunction_t = size_t(size_t, const KeyType&);
template< class KeyType, class ValueType, int nHashGroups,
hashFunction_t<KeyType> hashFunction >
class HashTable
{
};
class Entity
{
//djb2
size_t stringHash(size_t nGroups, const std::string& key)
{
unsigned long hash = 5381;
const char* str = key.c_str();
int c = 0;
while (c = *str++)
hash = ((hash << 5) + hash) + c;
return hash % nGroups;
}
HashTable <std::string, int, 10, stringHash> ht;
};
int main()
{
Entity{};
}
I would prefer to hide stringHash function inside the Entity class as a private function but doing that gives me an error:
Error (active) E0458 argument of type
"size_t (Entity::*)(size_t nGroups, const std::string &key)"
is incompatible with template parameter of type
"hashFunction_t<std::string> *"
How can I do this?
The problem is that you are trying to use a pointer-to-member as a type template parameter, and this is not supported, basically because when you define a type you don't bind that type to any specific object.
When (as suggested in a comment) you make stringHash static, then you no longer need the object, so it can be used to define the type.
If you still need to have stringHash from a non-static member, then you can change the template to something like the below. Be aware that you have to pass the object to the HashTable in order to call the hashFunction. Also, keep an eye on the syntax to call it.
template<class KeyType, class Obj> using hashFunction_t =
size_t(Obj::*)(size_t, const KeyType&);
template< class KeyType, class ValueType, int nHashGroups,
class Obj, hashFunction_t<KeyType, Obj> hashFunction>
class HashTable
{
public:
explicit HashTable(Obj& obj) : m_obj{obj} {
(m_obj.*hashFunction)(10, ""); // arguments just for illustrative purposes
}
private:
Obj& m_obj; // keep a reference to the object to call the method
// be careful with dangling references
};
class Entity
{
size_t stringHash(size_t nGroups, const std::string& key)
/* ... */
// Pass a reference to the object
HashTable <std::string, int, 10, Entity, &Entity::stringHash> ht{*this};
};
I'm going through some template sample code and there's one thing I don't get.
Take a template methode:
template<class Seq, class T, class R>
void apply(Seq &sq, R(T::*f)() const) {
typename Seq::iterator it = sq.begin();
while(sq.end() != it) {
((*it++)->*f)();
}
}
A sample class:
class MyClass {
public:
MyClass() {}
void doSomething() const {
std::cout << "doing stuff..." << std::endl;
}
};
And the test code:
void testMyClass() {
vector<MyClass*> v;
for(size_t i = 0; i < 5; ++i) {
v.push_back(new MyClass());
}
// call a member methode on all elements in container
apply(v, &MyClass::doSomething);
}
I would be grateful if someone could explain me what is that class R for, as defined in the template definition?
class R refers to the return type of the function pointer being passed to the function apply. It is automatically deduced from the actually passed function pointer type, so you never really need to care about it when calling apply.
The implementation of apply discards the return value of the function, so you could simply force the passed function to return void:
template<class Seq, class T>
void apply(Seq &sq, void(T::*f)() const) {
typename Seq::iterator it = sq.begin();
while(sq.end() != it) {
((*it++)->*f)();
}
}
However, now you restrict the call site to only pass such function pointers. Sadly, a pointer to a function which returns something isn't implcitly convertible to one which doesn't, although it would be pretty "intuitive".
So when you take a function pointer as an argument, and you don't care about the return type, it's better to accept "any" return type than "none".
class R in the template is used to deduce the return type of the function. In your case, it is deduced to be of type void.
I am trying to create a template function that is overloaded for pointer and non pointers. I did this and it works.
template<class D, class V>
bool Same(D d, V v){ return d == v; }
template<class D, class V>
bool Same(D* d, V v) { return *d==v;}
Now I want to extend it such that a templated container is a paramater and there must be one version for the container with pointer and other with the container for non pointers. I am not able to figure it out. I tried this but it won't work.
template< template<class> class Container, class Data, class Value>
bool func(Container<Data> &c, Value v)
{
return c[0] == v;
}
template< template<class> class Container, class Data, class Value>
bool func(Container<Data*> &c, Value v)
{
return *c[0] == v;
}
The error c2040 says int* differs in level of indirection from int and points to the first function.
How can I get it to work?
Rest of thecode
template<class D>
class Vec
{
std::vector<D> m_vec;
public:
void push_back(D d) { m_vec.push_back(d); }
D operator[](int i) { return m_vec[i]; }
};
void test_template()
{
Same<int, int>(2,3);
Info i = {4};
Same<Info, int>(i, 2);
Info ii = {2 };
Info *pi = ⅈ
Same<Info, int>(pi, 2);
Vec<int> iv;
iv.push_back(3);
func<Vec, int, int>(iv, 3);
Vec<int*> pv;
pv.push_back(new int(3));
func<Vec, int*, int>(pv, 3);
}
For the second call to func, the second template parameter should just be int, not int *. Otherwise, the second func declaratino will look for a Vec<int **> as the first template argument (since it has its own pointer).
func<Vec, int, int>(pv, 3);
EDIT: as DyP mentioned, you can also leave out the template arguments completely, as the compiler should be able to deduce them from the actual function arguments.
I was trying to built atop the thread here: Variable length template arguments list?
to have a default Functor class, this is only of academic interest. My goal is to build a generic Fucntor class: given a class name, method name and argument types(of variable length), it builds a class that has an operator() method which takes variable number of arguments of type specified in template args and takes a pointer and applies the given method. Imagine a class thus:
class MyClass
{
public:
float Fraction( float n, int m)
{
return n/m;
}
int Increment(int n)
{
return n+1;
}
} ;
And a templatized functor class that can be used in any function thus:
int k = FunctorClass<MyClass, Increment, int, int /*return type*/> (3);
assert(k == 4);
float l = FunctorClass<MyClass, Fraction, float, int, float, /*return type*/> (4,3);
assert(l == (4/3));
Can such a functor class be constructed?
Sidenote: Cant use Variadic templates, (building in VS2010, no ... template arguments)
Thanks for the help
This is certainly doable, e.g. Boost bind() uses this approach under the hood. Without variadics you won't get full generality, however, because you will be limited to a fixed number of template arguments and you need to type the implementation for each different number of arguments you want to support. Also, without rvalue references you won't get perfect forwarding.
That said, the way you are trying to use it won't work: when stating the member functions, you can't just name them. You need to obtain the correct member function point using e.g. &MyClass::Increment and &MyClass::Fraction. If the member function is overloaded, you need to disambiguate it.
Since you apparently want to enable the use of this function object for non-static member functions, you also need to provide an object on which the member function is to be called. The most reasonable approach for this is to pass a reference to the object as a constructor argument of the function object class and to store it to be used whenever the function is being called. That is, the use looks somewhat different but it can be simplified with some sort of factory function. Here is a version which adjusts the various things and implements a corresponding function object template:
#include <cassert>
// -----------------------------------------------------------------------------
template <typename T, T> class FunctorClass;
template <typename RC, typename Class,
RC (Class::*Member)()>
class FunctorClass<RC (Class::*)(), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()() const { return (this->object_->*Member)(); }
private:
Class* object_;
};
template <typename RC, typename Class, typename A0,
RC (Class::*Member)(A0)>
class FunctorClass<RC (Class::*)(A0), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()(A0 a0) const { return (this->object_->*Member)(a0); }
private:
Class* object_;
};
template <typename RC, typename Class, typename A0, typename A1,
RC (Class::*Member)(A0, A1)>
class FunctorClass<RC (Class::*)(A0, A1), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()(A0 a0, A1 a1) const { return (this->object_->*Member)(a0, a1); }
private:
Class* object_;
};
// -----------------------------------------------------------------------------
class MyClass
{
public:
int foo() { return 17; }
float Fraction( float n, int m)
{
return n/m;
}
int Increment(int n)
{
return n+1;
}
};
int main()
{
MyClass object;
int i = FunctorClass<int (MyClass::*)(), &MyClass::foo>(object)();
assert(i == 17);
int k = FunctorClass<int (MyClass::*)(int), &MyClass::Increment>(object)(3);
assert(k == 4);
float l = FunctorClass<float (MyClass::*)(float, int), &MyClass::Fraction>(object)(4,3);
assert(l == (4.0f/3));
}
I'm not sure you would need variadics to pull this off. Consider the following interface...
template < typename RETURN_TYPE >
class iFunctor abstract {
public:
virtual RETURN_TYPE operator () ( void ) = 0;
};
Abstract interfaces are not full-blown classes, they can contain a partial implementation such as function signatures and some data members. With the template, you can generalized a return type. But what about the argument list you say?
Note how there is no constructor in the interface. In your concrete class (or derived classes) you can pass the burden of variable argument lists to the constructor, like so...
template < typename TYPE >
class ConcreteFunctor_add : public iFunctor < TYPE > {
private:
int A;
int B;
public:
explicit ConcreteFunctor_add ( const int &a, const int &b ) : A(a), B(b) {};
TYPE operator () ( void ) { return ( A + B ); };
};
You deal with the argument list on a case by case basis through the constructor.
The explicit constructor requires an argument list upon declaration, so you'll get your variable list here. So in practice...
ConcreteFunctor_add < int > addInteger ( 10, 10 );
addInteger();
...and you'd be cool.
I'll begin with a context that will lead to the actual question.
I'm trying to build a class whose every instance will manage how data is tied together into objects.
The class should preferably contain methods:
class DataManager {
Object CreateObject();
void DestoryObject();
template<typename DataType>
DataType* AddDataToObject(Object o)
template<typename DataType>
DataType* GetDataForObject(Object o)
template<typename DataType>
void RemoveDataFromObject(Object o)
};
Object in the code above is just some identifier - int at this point and does not contain any data or methods (this should not change). DataType used above can be basically any class, however the general situation is that this is just a struct with no methods. The complete list of things that can be used as DataType is known at compile time but should not be encoded as it changes quite often.
The two goals I try to achieve are:
- Maintainability/Speed - The user should be able to add new DataType structures without modifying this code
- Speed - should be as fast as possible :)
Now the best thing idea I had so far is to make a container classes:
class ContainerBase;
template<typename DataType>
class DataTypeContainer : ContainerBase;
The data structure then would be something like:
map< DataTypeType, map< Object, ContainerBase* > >
Sow how can one achieve this?
Would boost::mpl::map help and how?
In essence this should be possible to do since all DataType's are known at compile time.
class DataManager {
struct internal_base { virtual ~internal_base() {} };
template<typename T> struct internal_data : public internal_base {
T t;
};
boost::unordered_map<Object, boost::unordered_map<std::string, boost::unique_ptr<internal_base>>> data;
public:
Object CreateObject() { return Object(); }
void DestroyObject(Object o) { data.erase(o); }
template<typename DataType> DataType* AddDataToObject(Object o, std::string name) {
internal_data<T>* ptr = new internal_data<T>();
data[o][name] = ptr;
return &ptr->t;
}
template<typename DataType> DataType* GetDataForObject(Object o, std::string name) {
internal_base* ptr = data[o][name].get();
if (internal_data<DataType>* dptr = dynamic_cast<internal_data<DataType>*>(ptr)) {
return &dptr->t;
else
return 0;
}
void RemoveDataFromObject(Object o, std::string name) {
data[o][name] = 0;
}
};
This code makes some assumptions- like default-construction of Object type, and that it is hashable. But it shouldn't be too difficult to modify. It would be substantially trickier to get defined behaviour if you want just one data member of each type associated with a specific Object, because you can't rely on RTTI to return unique names for each possible DataType.
If you want the equivalent of a map from types to values, and it can be global, you can use static members:
template <typename T>
struct DataManager {
static std::map<void*, Object> this_type_map;
};
plus appropriate definitions of DataManager<T>::this_type_map for the various values of T (but those definitions don't need to be in the same source file). After that, you can create type map objects using (void*)(new int), free them using delete (int*)(m), and look up the object for an instance m and a type T using DataManager<T>::this_type_map[m]. You would want to wrap these in functions or objects, of course. Note that you can have a different type than Object as the value type in the map, including (using template specializations) having a different value type for each key type in the type map.
I think that you need the std::tuple c++11 or playing with boost::tuple for c++ 03
template<typename T>
struct Entry{
T t;
};
int main(int argc, char **argv) {
std::tuple< int, float, double, Entry<int> > objects;
std::get<0>(objects) = 3;
std::get<3>(objects).t = 5;
//
utils::get< Entry<int> >(object).t = 5;
return 0;
}
get by type can be implemented like here:
https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/Utilities/MPL/Tuple.h
You could create a tuple with the mapping between your types like that:
template < std::size_t sz, typename... Types >
struct TypeMap {
TypeMap (std::array< std::tuple< Types... >, sz > m) : mapping (m) {
}
std::array< std::tuple< Types... >, sz > mapping;
};
Then specify a function to convert
template < typename To, typename From, std::size_t sz, typename... T >
To convert (From from, TypeMap< sz, T... > m) {
for (auto entry : m.mapping) {
if (utils::get< From > (entry) == from) {
return utils::get< To > (entry); //Tricky part here
}
}
throw std::logic_error ("No entry in the typemap");
}
Then specify the mapping
const auto map = TypeMap{{std::make_tuple (red, "red", 1),
std::make_tuple (green, "green", 2),
std::make_tuple (blue, "blue", 3)}};
and finally you can call your convert function and convert any type to any other type ;)
See my article here:
https://cpptelepathy.wordpress.com/
You would need this file
https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/MPL/Tuple.h
for util::get