Reputation: 123
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
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
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