-
July 29th, 2016, 03:16 AM
#1
Template specialisation error
Does anyone know if there's a way to make this specialisation work?
I have a feeling that it is not possible to do what I want. Can anyone prove me wrong?
The previous incarnation of the original code passes the member function pointer as a parameter in the constructor.
With this code I am attempting to get the address at compile time.
Code:
template <typename TObject, typename TParameter, void(TObject::*p_function)(TParameter)>
class function
{
public:
function(TObject& object)
: p_object(&object)
{
}
void operator ()(TParameter data)
{
// Call the object's member function with the data.
(p_object->*p_function)(data);
}
private:
TObject* p_object;
};
// Specialisation
template <typename TObject, void(TObject::*p_function)(void)>
class function<TObject, void, p_function> // error: invalid parameter type 'void'
{
public:
function(TObject& object)
: p_object(&object)
{
}
void operator ()(void)
{
// Call the object's member function.
(p_object->*p_function)();
}
private:
TObject* p_object;
};
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
-
July 29th, 2016, 09:27 AM
#2
Re: Template specialisation error
Originally Posted by JohnW@Wessex
Does anyone know if there's a way to make this specialisation work?
I have a feeling that it is not possible to do what I want. Can anyone prove me wrong?
The previous incarnation of the original code passes the member function pointer as a parameter in the constructor.
With this code I am attempting to get the address at compile time.
Code:
template <typename TObject, typename TParameter, void(TObject::*p_function)(TParameter)>
class function
{
public:
function(TObject& object)
: p_object(&object)
{
}
void operator ()(TParameter data)
{
// Call the object's member function with the data.
(p_object->*p_function)(data);
}
private:
TObject* p_object;
};
// Specialisation
template <typename TObject, void(TObject::*p_function)(void)>
class function<TObject, void, p_function> // error: invalid parameter type 'void'
{
public:
function(TObject& object)
: p_object(&object)
{
}
void operator ()(void)
{
// Call the object's member function.
(p_object->*p_function)();
}
private:
TObject* p_object;
};
The issue is that you can only use "(void)" at syntax level, for C compatibility. But inside templates, you are way past that phase, and the compiler will not accept passing the *actual* void type.
One other thing I tried to do was to declare a base template, with an extra type "PType" that is the function pointer type, and then try to specialize on the type of the function pointer. The odd thing is that the compiler never saw the specialization, but when I removed the base template, it did see it...?
Anyways, if you are OK with nesting templates, then this is something that varargs could solve in a more generic way:
Code:
#include <iostream>
using namespace std;
struct Object {
void foo(int);
void bar();
void baz(long, long);
void baz(long, long, long);
};
template<typename TObject, typename... TParameter>
class function
{
public:
template<void(TObject::*p_function)(TParameter...)>
class instance {
public:
instance(TObject& object)
: p_object(&object)
{
}
void operator ()(TParameter... data)
{
// Call the object's member function with the data.
(p_object->*p_function)(data...);
}
private:
TObject* p_object;
};
};
int main()
{
Object object;\
function<Object, int>::instance<&Object::foo> for_foo(object);
function<Object>::instance<&Object::bar> for_bar(object);
function<Object, long, long>::instance<&Object::baz> for_baz1(object);
function<Object, long, long, long>::instance<&Object::baz> for_baz2(object);
cout << "Hello World" << endl;
}
The main issue is that the parameter types must be declared before the function type, but by them you are not allowed to have any more parameters. The workaround here is a nested class to add more parameters. The end call is kind of clunky, but could be solved with "auto"+helper function, or maybe template aliases.
Note that this approach handles any amount of arguments, and overloads.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
July 29th, 2016, 09:56 AM
#3
Re: Template specialisation error
Alternatively, you could use something such as function_traits to extract the arguments of your function pointer directly.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
August 2nd, 2016, 01:19 PM
#4
Re: Template specialisation error
So, have you had much luck on your end finding a better solution?
I'm pretty sure there could be ways for you to define the template in the form:
function<std::function<args>, actual_function> your_instance;
But have been unable to do this.
Alternativelly, I'd still be interested in knowing if you succeeded in providing "overloads" so that this actually works:
function<TObject, actual_function> your_instance0;
function<TObject, ARG_TYPE_ONE, actual_function> your_instance1;
function<TObject, ARG_TYPE_ONE, ARG_TYPE_TWO, actual_function> your_instance1;
Because the last argument is not a type, this should be possible. I'd also be very interested in getting something like that to work.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
August 3rd, 2016, 07:39 AM
#5
Re: Template specialisation error
Originally Posted by monarch_dodra
I'm pretty sure there could be ways for you to define the template in the form:
function<std::function<args>, actual_function> your_instance;
something like
Code:
template < typename... T >
struct args {};
template < typename T, typename Args >
struct function_ptr
{
};
template < typename T, typename... Args >
struct function_ptr<T,args<Args...>>
{
typedef void (T::*type)(Args...);
};
template < typename T, typename Args, typename function_ptr<T,Args>::type fptr >
struct function
{
// ...
};
// function< foo, args<int>, &foo::bar >
?
-
August 3rd, 2016, 07:47 AM
#6
Re: Template specialisation error
or, more concisely
Code:
template < typename Signature >
struct function_ptr
{
};
template < typename T, typename... Args >
struct function_ptr<T(Args...)>
{
typedef void (T::*type)(Args...);
};
template < typename Signature, typename function_ptr<Signature>::type fptr >
struct function
{
// ...
};
// function< foo(int), &foo::bar >
-
August 3rd, 2016, 11:38 AM
#7
Re: Template specialisation error
Originally Posted by superbonzo
or, more concisely
Code:
template < typename Signature >
struct function_ptr
{
};
template < typename T, typename... Args >
struct function_ptr<T(Args...)>
{
typedef void (T::*type)(Args...);
};
template < typename Signature, typename function_ptr<Signature>::type fptr >
struct function
{
// ...
};
// function< foo(int), &foo::bar >
That works, but the issue (I had) remains that we (I) can't extract "Args" back out from function_ptr (or signature).
I've been able to extract the "T", but how do you implement operator()?
Code:
void operator ()(Args... args) // HERE
{
(p_object->*fptr)(args);
}
AFAIK, you can't typedef a vararg, so you can't extract the args back out of Signature, even with traits...?
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
August 3rd, 2016, 04:27 PM
#8
Re: Template specialisation error
Originally Posted by monarch_dodra
That works, but the issue (I had) remains that we (I) can't extract "Args" back out from function_ptr (or signature).
you can do it ( unless I'm missing something, just inherit operator() from a suitably specialized implementation base class ) but should you ? I think a perfectly forwarding operator() would be easier to write and more correct for the OP use case ...
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|