ramafe
ramafe

Reputation: 123

check function passed to template has class in arguments

This is a little hard to explain, In my class i have a create function that takes a pointer and arguments I want to be able to check if the function im passing to that function has the ClassPointer as its 1st argument if so automaticly add this to the function inside "create" if not just add the normal functions arguments if any,like im doing

       template <typename Function, typename... Arguments>
        void SomeClass::create(HWND hWnd, Function func, Arguments&&... args)
        {
            // check if function's 1st argument = class pointer

            std::function<void()> function = std::function<void()>(std::bind(std::forward<Function>(func), this, std::forward<Arguments>(args)...)); 

            // else

            std::function<void()> function = std::function<void()>(std::bind(std::forward<Function>(func), std::forward<Arguments>(args)...)); 
        }

        void ThreadProc1(SomeClass* pThis, HWND hwnd)
        {
             // do some stuff in here
        }

        void ThreadProc2(HWND hwnd)
        {
             // do some stuff in here
        }

test.Create(hwnd, ThreadProc1, hwnd);
test.Create(hwnd, ThreadProc2, hwnd);

Upvotes: 1

Views: 129

Answers (2)

W.F.
W.F.

Reputation: 13988

The problem can be more generalized. You can ask how to determine if N-th argument of the function is of a given type. To statically gain the answer on this question you could create SFINAE helper struct nth_param_is as follows:

#include <type_traits>
#include <functional>
#include <iostream>

using namespace std;

typedef int HWND;


template<int N, class T, class... Args>
struct nth_template_param_is: false_type { };

template<int N, class T, class First, class... Others>
struct nth_template_param_is<N, T, First, Others...>: nth_template_param_is<N-1, T, Others...> { };

template<class T, class First, class... Others>
struct nth_template_param_is<0, T, First, Others...>: is_same<T, First> { };

template<int N, class T, class Foo>
struct nth_param_is: false_type {};

template<int N, class T, class Result, class... Args>
struct nth_param_is<N, T, Result(*)(Args...)>: nth_template_param_is<N, T, Args...> { };

struct SomeClass {

      template <typename Function, typename... Arguments>
        typename enable_if<nth_param_is<0, SomeClass *, Function>::value >::type create(HWND hWnd, Function func, Arguments&&... args)
        {
            // check if function's 1st argument = class pointer

            std::function<void()> function = std::function<void()>(std::bind(std::forward<Function>(func), this, std::forward<Arguments>(args)...)); 
            cout << "function with 1st argument = class pointer" << endl;
            function();
        }
      template <typename Function, typename... Arguments>
        typename enable_if<!nth_param_is<0, SomeClass *, Function>::value >::type create(HWND hWnd, Function func, Arguments&&... args)
        {
            // else
            cout << "function with 1st argument = non-class pointer" << endl;
            std::function<void()> function = std::function<void()>(std::bind(std::forward<Function>(func), std::forward<Arguments>(args)...)); 
            function();
        }
};
        void ThreadProc1(SomeClass* pThis, HWND hwnd)
        {
             cout << "ThreadProc1 invoked" << endl;
             // do some stuff in here
        }

        void ThreadProc2(HWND hwnd)
        {

             cout << "ThreadProc2 invoked" << endl;
             // do some stuff in here
        }



int main() {
HWND hwnd;
SomeClass test;
test.create(hwnd, ThreadProc1, hwnd);
test.create(hwnd, ThreadProc2, hwnd);
}

Edit:

I moved the functionality between header files and everything works just fine.
Example:

my_traits.h:

#ifndef MY_TRAITS_H
#define MY_TRAITS_H

#include <type_traits>

template<int N, class T, class... Args>
struct nth_template_param_is: std::false_type { };

template<int N, class T, class First, class... Others>
struct nth_template_param_is<N, T, First, Others...>: nth_template_param_is<N-1, T, Others...> { };

template<class T, class First, class... Others>
struct nth_template_param_is<0, T, First, Others...>: std::is_same<T, First> { };

template<int N, class T, class Foo>
struct nth_param_is: std::false_type {};

template<int N, class T, class Result, class... Args>
struct nth_param_is<N, T, Result(*)(Args...)>: nth_template_param_is<N, T, Args...> { };

#endif

some_class.h:

#ifndef SOME_CLASS_H
#define SOME_CLASS_H

#include <type_traits>
#include <iostream>
#include <functional>
#include "my_traits.h"

typedef int HWND;

struct SomeClass {

   // check if function's 1st argument = class pointer
   template <typename Function, typename... Arguments>
   typename std::enable_if<nth_param_is<0, SomeClass *, Function>::value >::type create(HWND hWnd, Function func, Arguments&&... args) {
      std::function<void()> function = std::function<void()>(std::bind(std::forward<Function>(func), this, std::forward<Arguments>(args)...)); 
      std::cout << "function with 1st argument = class pointer" << std::endl;
      function();
   }
   template <typename Function, typename... Arguments>
   typename std::enable_if<!nth_param_is<0, SomeClass *, Function>::value >::type create(HWND hWnd, Function func, Arguments&&... args) {
      std::cout << "function with 1st argument = non-class pointer" << std::endl;
      std::function<void()> function = std::function<void()>(std::bind(std::forward<Function>(func), std::forward<Arguments>(args)...)); 
      function();
   }

};

#endif

usage.cc:

#include <iostream>
#include "some_class.h"

void ThreadProc1(SomeClass* pThis, HWND hwnd) {
     std::cout << "ThreadProc1 invoked" << std::endl;
     // do some stuff in here
}
void ThreadProc2(HWND hwnd) {    
     std::cout << "ThreadProc2 invoked" << std::endl;
     // do some stuff in here
}

void ThreadProc3(SomeClass* pThis, int arg1, int arg2) {
     std::cout << "ThreadProc3 invoked" << std::endl;
     // do some stuff in here
}

int main() {
   HWND hwnd;
   SomeClass test;
   test.create(hwnd, ThreadProc1, hwnd);
   test.create(hwnd, ThreadProc2, hwnd);
   test.create(hwnd, ThreadProc3, 1, 2);
}

compilation:

g++ -std=c++11 usage.cc

usage:

./a.out

output:

function with 1st argument = class pointer
ThreadProc1 invoked
function with 1st argument = non-class pointer
ThreadProc2 invoked
function with 1st argument = class pointer
ThreadProc3 invoked

Upvotes: 1

Daniel Protopopov
Daniel Protopopov

Reputation: 7236

I believe std::is_same may be of use for you as per previous question at https://stackoverflow.com/a/13636569/696034

Upvotes: 0

Related Questions