Use member function as template argument to create a static wrapper - function

I'm trying to write a c++11 wrapper around a C API, and basically there is a way to register notifications with a static function pointer, which also passes me back an "opaque" pointer, which are provided at a later point, basically a pointer to classes I create, in this example the class foo. Basically, I'm trying to create a static function `helper<..>::call that has the API's signature, but generates code to call my member function on the instance that the c++ wrapper created, and is passed in through an "opaque" pointer along with it. This static function then also converts the arguments when finally calling the member function.
I seem to have this almost working, but I'm having trouble creating a "nicer" public function register_handler in this example, which hides the "uglier" internals. This is the error I'm getting:
test.cpp:154:37: error: no matching function for call to ‘register_handler<&foo::bar>(const char [6])’
154 | register_handler<&foo::bar>("test2"); // <-- trying to wrap it into a function so I can use only one template argument
| ^
test.cpp:137:6: note: candidate: ‘template<class T, class R, class ... Args, R (T::* Func)(Args ...)> void register_handler(const char*)’
137 | void register_handler(const char* name)
| ^~~~~~~~~~~~~~~~
This is my test code:
#include <iostream>
#include <memory>
#include <vector>
#include <map>
#include <cassert>
// inspired by https://stackoverflow.com/a/7943765/2129246
template <typename T>
struct func_traits:
public func_traits<decltype(&T::operator())>
{
};
template <typename R, typename... Args>
struct func_traits<R(*)(Args...)>
{
enum { arity = sizeof...(Args) };
typedef R result_type;
using all_args = std::tuple<Args...>;
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
};
template <typename C, typename R, typename... Args>
struct func_traits<R(C::*)(Args...) const>
{
enum { arity = sizeof...(Args) };
typedef C class_type;
typedef R result_type;
using all_args = std::tuple<Args...>;
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
};
template< std::size_t... Ns >
struct indices {
typedef indices< Ns..., sizeof...( Ns ) > next;
};
template< std::size_t N >
struct make_indices {
typedef typename make_indices< N - 1 >::type::next type;
};
template<>
struct make_indices< 0 > {
typedef indices<> type;
};
struct value
{
std::string str_;
template <typename T>
value(T val):
str_(std::to_string(val))
{
}
value(const char* str):
str_(str)
{
}
value(const std::string& str):
str_(str)
{
}
operator int() const
{
return std::stoi(str_);
}
operator double() const
{
return std::stof(str_);
}
operator std::string() const
{
return str_;
}
};
std::map<std::string, void(*)(void*, const std::vector<value>&)> g_handlers;
template <typename T, T>
struct helper;
template <typename T, typename R, typename... Args, R(T::*Func)(Args...)>
struct helper<R(T::*)(Args...), Func>
{
template <size_t... Is>
static void expand(T* obj, const std::vector<value>& args, indices<Is...>)
{
assert(sizeof...(Is) <= args.size());
(obj->*Func)((args[Is])...);
}
static void call(void *p, const std::vector<value>& args)
{
T* obj = reinterpret_cast<T*>(p);
expand(obj, args, typename make_indices<sizeof...(Args)>::type());
}
static void reg_handler(const char* name)
{
g_handlers.insert(std::make_pair(name, call));
};
};
template <typename Obj>
void call_handler(Obj& obj, const char* name, const std::vector<value>& args)
{
auto it = g_handlers.find(name);
if (it != g_handlers.end())
it->second(reinterpret_cast<void*>(&obj), args);
else
std::cout << "handler not registered: " << name << std::endl;
}
// The code below somehow doesn't ever match this template
template <typename T, typename R, typename... Args, R(T::*Func)(Args...)>
void register_handler(const char* name)
{
helper<R(T::*)(Args...), Func>::reg_handler(name);
}
struct foo
{
void bar(int v, const std::string& str, double f)
{
std::cout << "bar: v=" << v << " str=" << str << " f=" << f << std::endl;
};
};
int main()
{
// register member function handlers before we have any instances
helper<decltype(&foo::bar), &foo::bar>::reg_handler("test"); // <-- works, but "ugly" and exposes internal implementation
register_handler<&foo::bar>("test2"); // <-- trying to wrap it into a function so I can use only one template argument
// now we have an instance
foo f;
// call the previously registered handler
call_handler(f, "test", {1, "2", 3.45});
call_handler(f, "test2", {1, "2", 3.45});
return 0;
}

The simple answer for C++11 is: You can't!
From C++17 you are able to use auto also for non type template parameters as a function pointer or member function pointer is not a type here and you have no syntax to describe your function pointer type.
In C++17 you can use it like this:
struct foo
{
void bar(){}
};
template <typename T, T>
struct helper;
template <typename T, typename R, typename... Args, R(T::*Func)(Args...)>
struct helper<R(T::*)(Args...), Func>
{
static void reg_handler(const char* name)
{
// ... here your code continues
}
};
template < auto T >
struct X
{
};
template <typename T, typename R, typename... Args, R(T::*Func)(Args...)>
struct X<Func>
{
static void register_handler( const char* name )
{
helper<R(T::*)(Args...), Func>::reg_handler(name);
}
};
int main()
{
X<&foo::bar>::register_handler("check");
}

Related

C++11 Specialize one version of variadic function

I'm trying to create a variadic function that takes any amount of arguments, but I'd like to specialize the case where only two arguments with iterators are passed in. Passing in two arguments of non-iterators, should still use the generic variadic version. I'm hitting a static_assert failure that I haven't been able to overcome. It seems like it's trying to evaluate the entire expression in with_iterator_args, which fails if the function has less than two arguments, rather than skipping the evaluation of the remainder when the check for 2 arguments already yielded false.
Is there a way to do this without adding two more overloads for the one and two argument case?
This is what I have so far:
#include <iostream>
#include <vector>
#include <tuple>
// inspired by https://stackoverflow.com/a/7943765/2129246
template <typename... Args>
struct args_traits
{
enum { arity = sizeof...(Args) };
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
};
// based on: https://stackoverflow.com/a/30766365/2129246
template <typename T>
struct is_iterator
{
static char test(...);
template <typename U,
typename=typename std::iterator_traits<U>::difference_type,
typename=typename std::iterator_traits<U>::pointer,
typename=typename std::iterator_traits<U>::reference,
typename=typename std::iterator_traits<U>::value_type,
typename=typename std::iterator_traits<U>::iterator_category
> static long test(U&&);
constexpr static bool value = std::is_same<decltype(test(std::declval<T>())),long>::value;
};
template<typename Arg1, typename Arg2>
struct is_iterator_args
{
constexpr static bool value = is_iterator<Arg1>::value && is_iterator<Arg2>::value;
};
template<typename... Args>
struct with_iterator_args
{
constexpr static bool value = args_traits<Args...>::arity == 2
&& is_iterator_args<typename args_traits<Args...>::template arg<0>::type, typename args_traits<Args...>::template arg<1>::type>::value;
};
template <typename T, typename... Args,
typename = typename std::enable_if<!with_iterator_args<Args...>::value>::type>
void some_func(T first, Args&&... args)
{
std::cout << "func(" << first << ") called with " << sizeof...(args) << " args" << std::endl;
}
template <typename T, typename Begin, typename End,
typename = typename std::enable_if<is_iterator_args<Begin, End>::value>::type>
void some_func(T first, Begin begin, End end)
{
std::cout << "func(" << first << ") called with iterators: " << std::distance(begin, end) << std::endl;
}
int main()
{
std::vector<int> v{1, 2, 3};
some_func(1, v.begin(), v.end()); // special case, using iterators
some_func(1, "arg2", 3, std::string("arg4"));
some_func(1, "arg2");
some_func(1);
some_func(1, "arg2", 3, std::string("arg4"), 5.67);
return 0;
}
This is what fails:
In file included from test.cpp:3:
/usr/include/c++/9/tuple: In instantiation of ‘struct std::tuple_element<0, std::tuple<> >’:
/usr/include/c++/9/tuple:1285:12: required from ‘struct std::tuple_element<1, std::tuple<const char (&)[5]> >’
test.cpp:14:69: required from ‘struct args_traits<const char (&)[5]>::arg<1>’
test.cpp:45:3: required from ‘constexpr const bool with_iterator_args<const char (&)[5]>::value’
test.cpp:49:37: required by substitution of ‘template<class T, class ... Args, class> void some_func(T, Args&& ...) [with T = int; Args = {const char (&)[5]}; <template-parameter-1-3> = <missing>]’
test.cpp:68:21: required from here
/usr/include/c++/9/tuple:1303:25: error: static assertion failed: tuple index is in range
1303 | static_assert(__i < tuple_size<tuple<>>::value,
| ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
The problem in your case is that both expression before and after && must compile - even if the expression after the && will not be used.
My first try was to leverage C++17 constexpr if.
template<typename... Args>
struct with_iterator_args
{
private:
constexpr static bool value_checker() {
if constexpr (args_traits<Args...>::arity == 2) {
return is_iterator_args<typename args_traits<Args...>::template arg<0>::type, typename args_traits<Args...>::template arg<1>::type>::value;
}
else {
return false;
}
}
public:
constexpr static bool value = value_checker();
};
If you need to stick with C++11, you could use std::conditional. Please note that I also use std::false_type and std::true_type.
template<typename... Args>
struct is_iterator_args :
std::conditional<is_iterator<typename args_traits<Args...>::template arg<0>::type>::value &&
is_iterator<typename args_traits<Args...>::template arg<1>::type>::value,
std::true_type, std::false_type>::type
{
};
template<typename... Args>
struct with_iterator_args :
std::conditional<sizeof...(Args) == 2, is_iterator_args<Args...>, std::false_type>::type
{
};
I seem to be able to only make it work by adding more overloads, and not using with_iterator_args:
template <typename T, typename... Args>
void some_func_common(T first, Args&&... args)
{
std::cout << "func(" << first << ") called with " << sizeof...(args) << " args" << std::endl;
}
template <typename T, typename A>
void some_func(T first, A arg)
{
some_func_common(first, arg);
}
template <typename T>
void some_func(T first)
{
some_func_common(first);
}
template <typename T, typename A1, typename A2, typename... Args,
typename = typename std::enable_if<!is_iterator_args<A1, A2>::value>::type>
void some_func(T first, A1 begin, A2 end, Args&&... args)
{
some_func_common(first, std::forward<A1>(begin), std::forward<A2>(end), std::forward<Args>(args)...);
}
template <typename T, typename Begin, typename End,
typename = typename std::enable_if<is_iterator_args<Begin, End>::value>::type>
void some_func(T first, Begin begin, End end)
{
std::cout << "func(" << first << ") called iterators: " << std::distance(begin, end) << std::endl;
}
It seems unnecessarily messy, though.

Dynamic function call through member function via map and arguments unpacking through template

I have tried code written on some link provided for dynamic function call , but unable to run code on machine .I tried to run code present at stackoverflow.com/questions/15764078/dynamically-creating-a-c-function-argument-list-at-runtime through member function.
It is is giving bad call exception while running :
Code snnippets
#include <iostream>
#include <functional>
#include <stdexcept>
#include <string>
#include <boost/any.hpp>
class Test;
class Test
{
public:
template <typename Ret, typename... Args>
Ret callfunc (std::function<Ret(Args...)> func, std::vector<boost::any> anyargs);
template <typename Ret>
Ret callfunc (std::function<Ret()> func, std::vector<boost::any> anyargs)
{
if (anyargs.size() > 0)
throw std::runtime_error("oops, argument list too long");
return func();
}
template <typename Ret, typename Arg0, typename... Args>
Ret callfunc (std::function<Ret(Arg0, Args...)> func, std::vector<boost::any>anyargs){
if (anyargs.size() == 0)
throw std::runtime_error("oops, argument list too short");
Arg0 arg0 = boost::any_cast<Arg0>(anyargs[0]);
anyargs.erase(anyargs.begin());
std::function<Ret(Args... args)> lambda =
([=](Args... args) -> Ret {
return func(arg0, args...);
});
return callfunc (lambda, anyargs);
}
template <typename Ret, typename... Args>
std::function<boost::any(std::vector<boost::any>)> adaptfunc (Ret (Test::*func)(Args...)) {
std::function<Ret(Test*,Args...)> stdfunc = func;
std::function<boost::any(std::vector<boost::any>)> result =
([=](std::vector<boost::any> anyargs) -> boost::any {
return boost::any(callfunc(stdfunc, anyargs));
});
return result;
}
int func1 (int a)
{
std::cout << "func1(" << a << ") = ";
return 33;
}
};
int main ()
{
Test a;
std::vector<std::function<boost::any(std::vector<boost::any>)>> fcs =
{
a.adaptfunc(&Test::func1)};
std::vector<std::vector<boost::any>> args =
{{777}};
// correct calls will succeed
for (int i = 0; i < fcs.size(); ++i)
std::cout << boost::any_cast<int>(fcs[i](args[i])) << std::endl;
return 0;
}
This code compiled successfully
But it failed to run and crashed
In main function for loop.
Function needs typecast according to their signature e.g.:
a.adaptfunc((int(*)(int))&Test::func1)};
After this typecast function call will not fail

Template __host__ __device__ calling host defined functions

During implementation of CUDA code I often need some utility functions, which will be called from device and also from host code. So I declare these functions as __host__ __device__. This is OK and possible device/host incompabilities can be handled by #ifdef CUDA_ARCH.
Problems come when the utility function is templated ie. by some functor type. If the template instance calls a __host__ function I get this warning:
calling a __host__ function from a __host__ __device__ function is not allowed
detected during instantiation of "int foo(const T &) [with T=HostObject]"
Only solution I know is to define the function twice - once for device and once for host code with different name (I cannot overload on __host__ __device__). But this means that there is code duplication and all other __host__ __device__ functions which will call it, must be also defined twice (even more code duplication).
Simplified example:
#include <cuda.h>
#include <iostream>
struct HostObject {
__host__
int value() const { return 42; }
};
struct DeviceObject {
__device__
int value() const { return 3; }
};
template <typename T>
__host__ __device__
int foo(const T &obj) {
return obj.value();
}
/*
template <typename T>
__host__
int foo_host(const T &obj) {
return obj.value();
}
template <typename T>
__device__
int foo_device(const T &obj) {
return obj.value();
}
*/
__global__ void kernel(int *data) {
data[threadIdx.x] = foo(DeviceObject());
}
int main() {
foo(HostObject());
int *data;
cudaMalloc((void**)&data, sizeof(int) * 64);
kernel<<<1, 64>>>(data);
cudaThreadSynchronize();
cudaFree(data);
}
Warning is caused by the foo(HostObject()); call inside the main() function.
foo_host<> and foo_device<> are possible replacements for the problematic foo<>.
Is there a better solution? Can I prevent instantion of foo() on the device side?
You cannot prevent instantiation of either half of a __host__ __device__ function template instantiation. If you instantiate the function by calling it on the host (device), the compiler will also instantiate the device (host) half.
The best you can do for your use case as of CUDA 7.0 is to suppress the warning using #pragma hd_warning_disable as in the following example and ensure that the function is not called incorrectly.
#include <iostream>
#include <cstdio>
#pragma hd_warning_disable
template<class Function>
__host__ __device__
void invoke(Function f)
{
f();
}
struct host_only
{
__host__
void operator()()
{
std::cout << "host_only()" << std::endl;
}
};
struct device_only
{
__device__
void operator()()
{
printf("device_only(): thread %d\n", threadIdx.x);
}
};
__global__
void kernel()
{
// use from device with device functor
invoke(device_only());
// XXX error
// invoke(host_only());
}
int main()
{
// use from host with host functor
invoke(host_only());
kernel<<<1,1>>>();
cudaDeviceSynchronize();
// XXX error
// invoke(device_only());
return 0;
}
I was struggling with the same problem, and found half of a solution. One can overload the host and device function by adding dummy template parameters to them.
In device code, the __device__ "overload" of f is called, in host code the __host__ "overload" of f is called.
Unfortunately, this makes f to a template function. In particular, for constructors this can make big problems (which I am still struggling with).
#include <type_traits>
#include <cstdio>
#ifndef __CUDA_ARCH__
static constexpr bool in_cuda_code = false;
#else
static constexpr bool in_cuda_code = true;
#endif
__device__ void g_device() { printf( "device\n" ); };
__host__ void g_host() { printf( "host\n" ); };
template< bool b = in_cuda_code > void f();
template<> __device__ void f<true>() { g_device(); }
template<> __host__ void f<false>() { g_host(); }
__global__ void kernel () {
f();
}
int main() {
f();
kernel<<<1,1>>>();
cudaDeviceSynchronize();
}

thrust copy_if with const source

My problem is in the following code:
The filter function compiles, and runs as it should when the source is not constant (the iterators are adjusted accordingly). However when I change the source to const, the compiler gives me the following error for the first two variables of the copy_if statement:
"the object has type qualifiers that are not compatible with the member function".
I believe there is a const to not const conversion error somewhere but frankly I have no idea where. Any help would be appreciated.
#include "thrust\device_vector.h"
#include "thrust\copy.h"
typedef thrust::device_vector<float>::const_iterator Dc_FloatIterator;
typedef thrust::device_vector<float>::iterator D_FloatIterator;
typedef thrust::device_vector<int>::const_iterator Dc_IntIterator;
typedef thrust::device_vector<int>::iterator D_IntIterator;
typedef thrust::tuple< Dc_IntIterator, Dc_IntIterator, Dc_FloatIterator> Dc_ListIteratorTuple;
typedef thrust::zip_iterator<Dc_ListIteratorTuple> Dc_ListIterator;//type of the class const iterator
typedef thrust::tuple< D_IntIterator, D_IntIterator, D_FloatIterator > D_ListIteratorTuple;
typedef thrust::zip_iterator<D_ListIteratorTuple> D_ListIterator;//type of the class iterator
struct selector{//selector functor for the copy if call
const int val;
selector(int _val) : val(_val) {}
__host__ __device__
bool operator()(const int& x ) {
return ( x == val );
}
};
class Foo{
public:
thrust::device_vector<int> ivec1;
thrust::device_vector<int> ivec2;
thrust::device_vector<float> fvec1;
Foo(){;}
~Foo(){;}
D_ListIterator begin(){//cast of begin iterator
return D_ListIterator(D_ListIteratorTuple( ivec1.begin(), ivec2.begin(), fvec1.begin() ));
}
D_ListIterator end(){//cast of end iterator
return D_ListIterator(D_ListIteratorTuple( ivec1.end(), ivec2.end(), fvec1.end() ));
}
Dc_ListIterator cbegin(){//cast of const begin iterator
return Dc_ListIterator(Dc_ListIteratorTuple( ivec1.cbegin(), ivec2.cbegin(), fvec1.cbegin() ));
}
Dc_ListIterator cend(){//cast of const end iterator
return Dc_ListIterator(Dc_ListIteratorTuple( ivec1.cend(), ivec2.cend(), fvec1.cend() ));
}
void const_filter( const Foo& TheOther, const int& target ){//doesnt work
//This function should copy those member of the vectors where
//the ivec2[i] == target is true
thrust::copy_if(
TheOther.cbegin(),
TheOther.cend(),
TheOther.ivec2.cbegin(),
this->begin(),
selector(target) );
}
void filter( Foo& TheOther, const int& target ){//works
//This function should copy those member of the vectors where
//the ivec2[i] == target is true
thrust::copy_if(
TheOther.begin(),
TheOther.end(),
TheOther.ivec2.cbegin(),
this->begin(),
selector(target) );
}
void insert(const int& one, const int& two,const float& three ){
ivec1.push_back(one);
ivec2.push_back(two);
fvec1.push_back(three);
}
int size(){
return ivec1.size();
}
};
bool CheckIfSublistIsConnected(const Foo& list,const int& sublist_num){
Foo tmp;
tmp.const_filter( list, sublist_num );
return (bool)tmp.size();//for symplicity, othervise here is a function that check if
//the edge list represents a connected graph
}
int main(void){
Foo list;
bool connected;
list.insert(10,2,1.0);
list.insert(11,2,1.0);
list.insert(12,2,1.0);
list.insert(10,3,1.0);
list.insert(10,3,1.0);
connected=CheckIfSublistIsConnected(list,2);
if( connected ) return 0;
else return -1;
}
I've found that replacing TheOther.cbegin() / .cend() with the folowing the compiler accepts it. This means I messed up somewhere in the typedef section, but where?
thrust::make_zip_iterator(
thrust::make_tuple(
TheOther.ivec1.cbegin(),
TheOther.ivec2.cbegin(),
TheOther.fvec1.cbegin() ))
As it comes out I've frogotten to add the const magic word at the definition of cend/cbegin.
Dc_ListIterator cbegin() const {
return Dc_ListIterator(Dc_ListIteratorTuple( ivec1.cbegin(), ivec2.cbegin(), fvec1.cbegin() ));
}
Dc_ListIterator cend() const {
return Dc_ListIterator(Dc_ListIteratorTuple( ivec1.cend(), ivec2.cend(), fvec1.cend() ));
}

error with function pointers usage in C

#include <stdio.h>
#include <string.h>
void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }
typedef struct {
void (*func0)(void);
void (*func1)(void);
}mainJT;
static const mainJT coreJT = {
core_func0,
core_func1
};
mainJT currJT;
int main()
{
currJT=coreJT;
coreJT.core_func0();
getchar();
return 0;
}
Please help me fix the errors, I am sure I am making some obvious mistakes. Thanks.
Your question isn't quite clear but I see what I can find.
typedef struct {
void (*func0)(void);
void (*func1)(void);
} mainJT;
Here you are declaring a struct with function pointer members func0 and func1. Then you are trying to define a coreJT variable via an initializer list:
static const mainJT coreJT = {
core_func0,
core_func1
};
But this doesn't work, because there are no functions called core_func0 or core_func1!
Also you try to call
coreJT.core_func0();
which is also incorrect since your struct doesn't have a member of name core_func0.
For a possible solution try renaming your functions like so:
void core_func1 (void) { printf( "1\n" ); }
void core_func0 (void) { printf( "0\n" ); }
and call your function pointer by
coreJT.func0();
i see lot of errors:
for eg: the correct way of initializing a structure is :
/* Define a type point to be a struct with integer members x, y */
typedef struct {
int x;
int y;
} point;
/* Define a variable p of type point, and initialize all its members inline! */
point p = {1,2};
so your part of the code is :
mainJT coreJT = {
core_func0;
core_func1;
};
completely wrong.
also where are the functions core_func1 core_func0 are declared and defined .i cannot see them.
i guess you first need to go through structures in c