c++ templated static class with a const array of function pointers - c++

So I really need a class with the following structure, where the class is templated and arr is an array of function pointers, but I can't seem to figure out the proper syntax:
--myclass.h--
#include <vector>
template <typename T>
class MyClass {
typedef void (*fptr)(std::vector<T> data);
static void foo(std::vector<T> data);
static void bar(std::vector<T> data);
static void baz(std::vector<T> data);
static const fptr arr[3];
};
--myclass.cpp--
#include "myclass.h"
#include <vector>
template <typename T> void MyClass<T>::foo(std::vector<T> data) { ... }
template <typename T> void MyClass<T>::bar(std::vector<T> data) { ... }
template <typename T> void MyClass<T>::baz(std::vector<T> data) { ... }
template <typename T> MyClass<T>::fptr MyClass<T>::arr[3] = { &foo, &bar, &baz };
If it helps, my ultimate goal is for a fourth member function to call either foo, bar, or baz from the array so I can avoid the overhead of multiple if-else statements (my actual implementation has closer to 50 of these functions). Is there a better way to do this?

fptr is declared const, so define it const too. Also, because Sort is a template, you need typename to refer to MyClass<T>::fptr.
template<typename T>
const typename MyClass<T>::fptr MyClass<T>::arr[] = { &foo, &bar, &baz };
Side note: you won't be able to put this definition or the definitions of your static functions in a source file since they are templates.
Demo
Moreover, consider using using instead of typedef, and std::array instead of a raw array:
using fptr = void (*)(std::vector<T>);
static const std::array<fptr, 3> arr;
// [...]
template<typename T>
const std::array<typename MyClass<T>::fptr, 3> MyClass<T>::arr = { &foo, &bar, &baz };
Demo
Is there a better way to do this?
Probably, but I can't say without more details abour what you want to do exactly.

Move the whole class template into the .hpp file and initialize arr with the same signature as it was declared:
template <typename T>
class MyClass {
typedef void (*fptr)(std::vector<T> data);
static void foo(std::vector<T> data) {}
static void bar(std::vector<T> data) {}
static void baz(std::vector<T> data) {}
static const fptr arr[3];
};
template <typename T>
const typename MyClass<T>::fptr MyClass<T>::arr[] = { &foo, &bar, &baz };
You may also define arr directly:
#include <iostream>
#include <vector>
#include <array>
template <typename T>
class MyClass {
typedef void (*fptr)(std::vector<T> data);
static void foo(std::vector<T> data) {
for(int i : data) std::cout << "foo " << i << "\n";
}
static void bar(std::vector<T> data) {
for(int i : data) std::cout << "bar " << i << "\n";
}
static void baz(std::vector<T> data) {
for(int i : data) std::cout << "baz " << i << "\n";
}
public:
static constexpr std::array<fptr,3> arr = { &foo, &bar, &baz };
};
int main() {
MyClass<int> a;
a.arr[0](std::vector<int>(1));
a.arr[1](std::vector<int>(2));
a.arr[2](std::vector<int>(3));
}
Output:
foo 0
bar 0
bar 0
baz 0
baz 0
baz 0

You can use std::function and store them into a vector. Here is what I have come up with so far.
#include <exception>
#include <iostream>
#include <functional>
#include <vector>
template<typename T>
class MyClass {
private:
std::vector<std::function<void(std::vector<T>)>> myFuncs_;
public:
MyClass() = default;
void addFunc( std::function<void(std::vector<T>)> func ) {
myFuncs_.push_back(func);
}
void caller(unsigned idx, std::vector<T> v ) {
return myFuncs_.at(idx)( v );
}
static void foo(std::vector<T> data) {
std::cout << "foo() called:\n";
for (auto& d : data)
std::cout << d << " ";
std::cout << '\n';
}
static void bar(std::vector<T> data) {
std::cout << "bar() called:\n";
for (auto& d : data)
std::cout << d << " ";
std::cout << '\n';
}
};
int main() {
try {
MyClass<int> myClass;
std::vector<int> a{ 1,3,5,7,9 };
std::vector<int> b{ 2,4,6,8,10 };
std::function<void(std::vector<int>)> funcA = MyClass<int>::foo;
std::function<void(std::vector<int>)> funcB = MyClass<int>::bar;
myClass.addFunc( funcA );
myClass.addFunc( funcB );
myClass.caller(0, a);
myClass.caller(1, b);
} catch( std::runtime_error& e ) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
-Output-
MyClass::foo() was called:
1 3 5 7 9
MyClass::bar() was called:
2 4 6 8 10
Not sure if this is exactly what you was looking for. In this example MyClass::caller(...) takes two parameters, the index into the vector for which function pointer you want, and the parameter or data that the function requires as input.

Related

C++ function specialization from class template

I have a class, classB which has several functions which I would like to specialize based on an enumerator template S.
I have the following example:
#include <iostream>
#include <string>
#include <array>
typedef std::array<double, 3> vec;
enum Op {Op1, Op2, Op3};
template<class T, enum Op S=Op1>
class classA
{
public:
class innerClassA
{
public:
void foo() const
{
std::cout <<"Operation 1" << std::endl;
}
};
};
template<class T>
class classB
{
public:
template <Op S = Op1>
void myFunc()
{
typename classA<T, S>::template innerClassA myInnerClassObj;
for (int i = 0; i < 10; i++)
myInnerClassObj.foo();
}
// Other functions the I would like to able to speciallize afterwards based on template S
void myFunc2() { std::cout << "Func 2" << std::endl; }
void myFunc3() { std::cout << "Func 3" << std::endl; }
};
template<>
void classA<vec, Op2>::innerClassA::foo() const
{
std::cout << "Operation 2" << std::endl;
}
template<>
void classA<vec, Op3>::innerClassA::foo() const
{
std::cout << "Operation 3" << std::endl;
}
int main(int argc, char** argv)
{
classB<vec> obj;
obj.myFunc();
obj.myFunc2();
obj.myFunc<Op2>();
obj.myFunc<Op3>();
return 0;
}
In the above example. The function myFunc has a template parameter based on the enumerator. In the main function, I can call the specialized version based on the value of the enumerator. I would also like to do the same for the other functions,myFunc2 however, always having to put:
template <Op S = Op1>
someFunction()
is quite bothersome. Is there any other way to specify that all functions in a class have a default template based on the enumerator?
Kind regards
No, there is not, apart from macros.
#define OPFUNC template<Op S = Op1> void
OPFUNC myFunc() {}
OPFUNC myFunc2() {}
...
#undef OPFUNC

typedef on a templated function with member usage

I have two functions which need to be exposed by the class and they look like this (more will follow):
void print_a(std::string s);
void print_b(std::string s, int val);
"Under the hood" they are doing the same exact thing namely doing a lookup in a map and passing the call parameters to the function pointer retrieved by the map:
#include <stdint.h>
#include <iostream>
#include <string>
#include <map>
class Thing{
private:
void do_a(){
std::cout << "hello";
}
//there might be also a method do_a_extended() which has a different key in the map
void do_b(int age){
std::cout << "my age is " << age;
}
typedef void (Thing::*do_stuff_a)();
typedef void (Thing::*do_stuff_b)(int);
std::map<std::string, do_stuff_a> a_table;
std::map<std::string, do_stuff_b> b_table;
public:
void print_a(std::string s){
do_stuff_a handler = a_table[s];
if(handler){
(this->*handler)();
}
}
void print_b(std::string s, int val){
do_stuff_b handler = b_table[s];
if(handler){
(this->*handler)(val);
}
}
};
I dislike the fact that there is a lot of boilerplate code involved. I wonder if its possible to pass a member into template so I can do this:
class Thing{
private:
void do_a(){
std::cout << "hello";
}
void do_b(int age){
std::cout << "my age is " << age;
}
typedef void (Thing::*do_stuff_a)();
typedef void (Thing::*do_stuff_b)(int);
std::map<std::string, do_stuff_a> a_table;
std::map<std::string, do_stuff_b> b_table;
template<<MAP_MEMBER>,typename ... PP>
void print_x(std::string s, PP &&... pp){
auto handler = <MAP_MEMBER>[s];
if(handler){
(this->*handler)(std::forward<PP>(pp) ...);
}
}
public:
typedef decltype(print_x<a_table>) print_a;
typedef decltype(print_x<b_table>) print_b;
};
Any ideas on how to get rid of boilerplate is appreciated.
No need to get complicated, just use your printers as wrappers that pass a member to a generic print method like so:
class Foo
{
int a;
char b;
template <typename M>
void Print (M & member)
{
// complicated function
}
public:
void PrintA ()
{
Print(a);
}
void PrintB ()
{
Print(b);
}
};
So in your example the public print functions become wrapper functions:
class Thing
{
// ...
template <typename T, typename ... PP>
void print (T & table, const std::string & key, PP && ... pp)
{
auto method = table[key];
if (method)
(this->*method)(std::forward<PP>(pp)...);
}
public:
template <typename ... PP>
void print_a (PP && ... pp)
{
print(a_table, std::forward<PP>(pp)...);
}
template <typename ... PP>
void print_b (PP && ... pp)
{
print(b_table, std::forward<PP>(pp)...);
}
};
These public methods should be inlined if you use -O3 optimisation.
Here's a running solution with less boilerplate and no need for metaprogramming:
#include <iostream>
#include <string>
#include <map>
class Thing
{
void do_a_1 ()
{
std::cout << "hello" << std::endl;
}
void do_a_2 ()
{
std::cout << "goodbye" << std::endl;
}
void do_b (int age)
{
std::cout << "my age is " << age << std::endl;
}
template <typename ... PP>
using MapMethod = std::map<std::string, void (Thing::*)(PP...)>;
MapMethod<> a_table;
MapMethod<int> b_table;
template <typename T>
void insert (T) {}
template <typename T, typename M, typename ... PP>
void insert (T & table, const std::string & key, M && method, PP && ... pp)
{
table.insert({key, method});
insert(table, pp...);
}
template <typename T, typename ... PP>
void print (const T & table, const std::string & key, PP && ... pp)
{
auto result = table.find(key);
if (result != table.end())
{
auto method = result->second;
(this->*method)(pp...);
}
}
public:
Thing ()
{
insert(a_table,
"apple", &Thing::do_a_1,
"banana", &Thing::do_a_2);
insert(b_table,
"ostrich", &Thing::do_b);
}
void print_a (const std::string & key)
{
print(a_table, key);
}
void print_b (const std::string & key, int val)
{
print(b_table, key, val);
}
};
int main ()
{
Thing t;
t.print_a("apple");
t.print_b("ostrich", 12);
t.print_a("banana");
t.print_a("Do nothing");
}
If somehow your wrapper methods are unavoidably repetitive in your real problem (perhaps perfect forwarding is getting tiresome), you could reduce boilerplate further with a macro to make the print methods:
class Thing
{
// private code is the same, except:
// there's no need for the generic print method anymore
public:
Thing ();
#define PRINT_MACRO(FUNCTION_NAME, MEMBER_TABLE) \
template <typename ... PP> \
void FUNCTION_NAME (const std::string & key, PP && ... pp) \
{ \
auto result = MEMBER_TABLE.find(key); \
if (result != MEMBER_TABLE.end()) \
{ \
auto method = result->second; \
(this->*method)(pp...); \
} \
}
PRINT_MACRO(print_a, a_table)
PRINT_MACRO(print_b, b_table)
#undef PRINT_MACRO
};
Lastly, are you sure that you wanted to use std::map instead of std::unordered_map? This problem suggests that you don't care about the ordering.
Macros or code generation are the way to go when you want to define things that require concatenating in identifiers.
In particular, since you also need to handle an arbitrary number of parameters in the generated code, I'd go with code generation.
You could extract the map to an extra class that can also handle searching and calling entries:
template <typename C, typename K, typename...Args>
class MemberFunctionCaller
{
private:
using FunctionType = void(C::*)(Args...);
using MapType = std::map<K, FunctionType>;
MapType registry;
public:
void Register(const K& key, FunctionType value)
{
registry[key] = value;
}
void Call(const K& key, C* self, const Args&...args)
{
auto iter = registry.find(key);
if(iter != registry.end())
{
FunctionType func = iter->second;
(self->*func)(args...);
}
}
};
A simple typedef would simplify the usage inside your "Thing"-class:
template <typename...Args>
using ThingFunctionCaller = MemberFunctionCaller<Thing, std::string, Args...>;
The thing class could look somewhat like this:
class Thing{
template <typename...Args>
using ThingFunctionCaller = MemberFunctionCaller<Thing, std::string, Args...>;
private:
void do_a(){
std::cout << "hello" << std::endl;
}
void do_b(int age){
std::cout << "my age is " << age << std::endl;
}
ThingFunctionCaller<> a_table;
ThingFunctionCaller<int> b_table;
public:
void print_a(std::string s){
a_table.Call(s, this);
}
void print_b(std::string s, int val){
b_table.Call(s, this, val);
}
};
And that's what it would look like in Action: https://gcc.godbolt.org/z/KM5a85
You could use a static template registry that stores the relation between name and member function.
This has other disadvantages but would work in your particular use case.
(With some additional coding you could even make this work more "natural").
template <typename C, typename...Args>
using MemberFunctionPointer = void(C::*)(Args...);
template <typename C, typename...Args>
class MemberFunctionCaller
{
private:
using FunctionType = MemberFunctionPointer<C, Args...>;
using MapType = std::map<std::string, FunctionType>;
static MapType& GetRegistry(){
static MapType registry;
return registry;
}
public:
static void Register(const std::string& key, FunctionType function)
{
auto& registry = GetRegistry();
registry[key] = function;
}
static void Call(const std::string& key, C* self, const Args&...args)
{
auto& registry = GetRegistry();
auto iter = registry.find(key);
if(iter != registry.end())
{
FunctionType func = iter->second;
(self->*func)(args...);
}
}
};
template <typename C>
class MemberFunctionRegistry
{
public:
template <typename...Args>
static void Register(const std::string& key, MemberFunctionPointer<C, Args...> function)
{
MemberFunctionCaller<C, Args...>::Register(key, function);
}
template <typename...Args>
static void Call(const std::string& key, C* self, const Args&...args)
{
MemberFunctionCaller<C, Args...>::Call(key, self, args...);
}
};
Your Thing class could look like this:
class Thing{
private:
void do_a(){
std::cout << "hello" << std::endl;
}
void do_a_extended(){
std::cout << "hello world" << std::endl;
}
void do_b(int age){
std::cout << "my age is " << age << std::endl;
}
MemberFunctionRegistry<Thing> registry;
public:
static void RegisterMemberFunctions()
{
MemberFunctionRegistry<Thing>::Register("A", &Thing::do_a);
MemberFunctionRegistry<Thing>::Register("AX", &Thing::do_a_extended);
MemberFunctionRegistry<Thing>::Register("B", &Thing::do_b);
}
template <typename...Args>
void print_x(std::string s, Args...args){
registry.Call(s, this, args...);
}
};
https://gcc.godbolt.org/z/fq5bez

Template detects if T is pointer or class

Considering the following code:
class MyClass
{
...
};
template <typename Object>
class List
{
public:
void insert(const Object & x)
{
// call when Object is MyClass
}
void insert(const Object & x)
{
// call when Object is MyClass*
}
}
int main()
{
MyClass a;
List<MyClass> lst;
List<MyClass*> plst;
lst.insert(a);
plst.insert(new Myclass);
return 0;
}
How to tell the compiler call different methods based on if the template is a class or a pointer?
How to fix the code above?
You can use a combination of std::is_pointer and std::enable_if:
#include <type_traits>
#include <iostream>
class MyClass
{
};
template <typename Object>
class List
{
public:
template<class T=Object>
void insert(T t, typename std::enable_if<std::is_pointer<T>::value >::type* = 0)
{
std::cout << "insert pointer" << std::endl;
}
template<class T=Object>
void insert(T t, typename std::enable_if<!std::is_pointer<T>::value >::type* = 0)
{
std::cout << "insert non-pointer" << std::endl;
}
};
int main()
{
MyClass a;
List<MyClass> lst;
List<MyClass*> plst;
lst.insert(a);
plst.insert(new MyClass());
return 0;
}
Live example: https://ideone.com/CK8Zdo
This will allow you to insert both pointers and non-pointers into a pointer or non-pointer list.
If you want to restrict that, you can use this:
#include <type_traits>
#include <iostream>
class MyClass
{
};
template <typename Object>
class List
{
public:
template<class T=Object>
void insert(T t, typename std::enable_if<std::is_same<T,Object>::value&&std::is_pointer<T>::value >::type* = 0)
{
std::cout << "insert pointer" << std::endl;
}
template<class T=Object>
void insert(const T& t, typename std::enable_if<std::is_same<T,Object>::value&&!std::is_pointer<T>::value >::type* = 0)
{
std::cout << "insert non-pointer" << std::endl;
}
};
int main()
{
MyClass a;
List<MyClass> lst;
List<MyClass*> plst;
lst.insert(a);
// plst.insert(a); // compiler error
// lst.insert(new MyClass()); // compiler error
plst.insert(new MyClass());
return 0;
}
Live example: https://ideone.com/3DtBfr
I'm aware that my answer is not exactly about what you are asking, but maybe it could help.
I believe your intention is to have List class with one insert method (not two of them) and behaviour of this method should depend on your template parameter. For this
you could write a specialization of your class for pointers. Then basic template would be used for non pointer types and specialization would be used for pointer types.
Your code would look like this:
template <typename Object>
class List
{
public:
void insert(const Object & x)
{
// call when Object is MyClass
}
};
template <typename Object>
class List<Object *>
{
public:
void insert(Object * x)
{
// call when Object is MyClass*
}
};
void insert(const Object & x)
{
M_insert(x, dispatcher<std::is_pointer<Object>::value> );
}
Inside List use a dispatcher
template <bool B> class dispatcher {};
using ObjectPtr = dispatcher<true>;
using ObjectValue = dispatcher<false>;
then dispatch to M_insert:
void M_insert(const Object &p, ObjectPtr) { // Object is a pointer }
void M_insert(const Object &p, ObjectValue) { // Object is not a pointer }
Live example here. But, I'd encourage you to determine whether you really need that and possibly fix your design accordingly.
This does the trick:
template <typename Object>
class List
{
public:
template<class C = Object>
void insert(const C & x)
{
// call when Object is MyClass
std::cout << "1" << "\n" ;
}
template<class P = Object*>
void insert(P* p)
{
// call when Object is MyClass*
std::cout << "2" << "\n" ;
}
} ;
Here is a working example.

C++ factoring tempate methods specialization of a template class, is that possible?

I have a template method inside a template class.
I read that a method can not be specialized without specialize the class before.
But I want to factorize some of theses methods, is it possible ?
Example :
class One {
public:
static const int number = 1;
};
class Two {
public:
static const int number = 2;
};
template<typename num> class A {
private:
num n;
public:
template<typename type>
void multiplyBy(); // by 1 if <int> or 1,5 if <float>
}; // A
template<> template<> void A<One>::multiplyBy<int>() {
std::cout << 1.0*n.number << std::endl;
}
template<> template<> void A<One>::multiplyBy<float>() {
std::cout << 1.5*n.number << std::endl;
}
template<> template<> void A<Two>::multiplyBy<int>() {
std::cout << 1.0*n.number << std::endl;
}
template<> template<> void A<Two>::multiplyBy<float>() {
std::cout << 1.5*n.number << std::endl;
}
int main() {
A<One> aOne;
A<Two> aTwo;
aOne.multiplyBy<int>(); // 1
aOne.multiplyBy<float>(); // 1.5
aTwo.multiplyBy<int>(); // 2
aTwo.multiplyBy<float>(); // 3
return 0;
}
A stackoverflow related question : C++ specialization of template function inside template class
In particular this comment : C++ specialization of template function inside template class
Have I to deduct than there is no way to factorize multiplyBy(), for one for int and an other for float ?
As english is not my natural language maybe I miss something simple, maybe a workaround with partial-specialization.
Edit : put A::n in private to match even better my problem.
You might use tag dispatching:
#include <iostream>
class One {
public:
static const int number = 1;
};
class Two {
public:
static const int number = 2;
};
template<typename num>
class A {
public:
num n;
private:
template<typename> struct Tag {};
void multiplyBy(Tag<int>) {
std::cout << 1.0*n.number << std::endl;
}
void multiplyBy(Tag<float>) {
std::cout << 1.5*n.number << std::endl;
}
public:
template<typename type>
void multiplyBy() {
multiplyBy(Tag<type>());
}
};
int main() {
A<One> aOne;
A<Two> aTwo;
aOne.multiplyBy<int>(); // 1
aOne.multiplyBy<float>(); // 1.5
aTwo.multiplyBy<int>(); // 2
aTwo.multiplyBy<float>(); // 3
return 0;
}
But I want to factorize some of theses methods, is it possible ?
You probably know that you cannot use:
template<> template<> void A<One>::multiplyBy<int>() {
std::cout << 1.0*n.number << std::endl;
}
without specializing A<One>.
You can do something along the lines of:
#include <iostream>
class One {
public:
static const int number = 1;
};
class Two {
public:
static const int number = 2;
};
template<typename num, typename type = int> struct MultiplyBy {
static void doit(num n)
{
std::cout << 1.0*n.number << std::endl;
}
};
template<typename num> struct MultiplyBy<num, float> {
static void doit(num n)
{
std::cout << 1.5*n.number << std::endl;
}
};
template<typename num> class A {
public:
num n;
template<typename type>
void multiplyBy()
{
MultiplyBy<num, type>::doit(n);
}
};
int main() {
A<One> aOne;
A<Two> aTwo;
aOne.multiplyBy<int>(); // 1
aOne.multiplyBy<float>(); // 1.5
aTwo.multiplyBy<int>(); // 2
aTwo.multiplyBy<float>(); // 3
return 0;
}

How can I instantiate class with Member function pointer as template arg

I have
template <void (*T)(Entity *), typename Caller>
class Updater
{
public:
Updater(Caller c):m_caller(c){}
void process(Entity * e)
{
(m_caller->*T)(e); //Is this right?
}
private:
Caller m_caller;
};
I understand I can instantiate it like
Foo f;
Updater<&Foo::Bar> updater(&f);
assuming that Foo has
void Foo::Bar(Entity *e);
but what if it has desired method tempated? Like this
template <typename T>
void Bar(T t);
how shoult I instanciate it? Like this:?
Foo f;
Updater<&Foo::Bar<Entity *>> updater(&f);
When I do this in my real code, I get
invalid template argument for ..., expected compile-time constant expression
So 2 questions:
1, is (m_caller->*T)(e); correct? If it is not, how shout i call it?
2, how can I instantiate it?
template <typename Caller, void (Caller::*Func)(Entity *)>
class Updater
{
public:
Updater(Caller *c):m_caller(c){}
void process(Entity * e)
{
(m_caller->*Func)(e); // use pointer to member operator ->*
}
private:
Caller *m_caller;
};
// call like this
Foo f;
Updater<Foo, &Foo::Bar> updater(&f);
edit:
user2k5 edited his answer, so I accepted it.
my previous msg:
Thanks to user2k5 I figured out the right working code,
working sample follows: (Foo2 can be replaced by Foo)
#include <iostream>
struct Entity { int i; };
template < typename Caller, void (Caller::*Func)(Entity *)>
class Updater
{
public:
Updater(Caller *c):m_caller(c){}
void process(Entity * e)
{
(m_caller->*Func)(e);
}
private:
Caller *m_caller;
};
struct Foo
{
void bar(Entity * e)
{
std::cout << e->i << std::endl;
}
};
struct Foo2
{
template <typename T>
void bar(T t)
{
std::cout << t->i << std::endl;
}
};
int main ()
{
Foo2 f;
Updater<Foo2, &Foo2::template bar<Entity *>> updater(&f);
Entity e;
e.i = 5;
updater.process(&e);
return 0;
}