26

I'm been grinding my head against an idea that is simple enough in my head, but I can't figure out how to implement in C++.

Normally, I can declare a class with a conversion operator like in this simple example:

class Foo { private: int _i; public: Foo( int i ) : _i(i) { } operator int( ) const { return i; } }; 

So now I can write awesome stuff like

int i = Foo(3); 

But in my particular case, I would like to provide an operator for converting an object to a function pointer (e.g. converting a Bar instance to a int(*)(int, int) function pointer). Here's what I initially tried:

class Bar { private: int (*_funcPtr)(int, int); public: Bar( int (*funcPtr)(int, int) ) : _funcPtr(funcPtr) { } operator int(*)(int, int) ( ) const { return _funcPtr; } }; 

But the operator function fails to compile, with these errors being generated:

expected identifier before '*' token '<invalid-operator>' declared as a function returning a function 

I have also tried simple variations on the above, such as surrounding the return type in parenthesis, but all these ideas have also failed.

Does anyone know what the syntax is for declaring a conversion-to-function-pointer operator method, or whether it is even possible to do so?

Note: I am compiling this with Code::Blocks using GCC 4.5.2. Answers involving some of the new C++0x concepts are also welcome.

Edit

In my strive for simplifying the example, I unintentionally left out one detail. It's a bit weird, but rather than strictly returning an int(*)(int,int) pointer, the conversion operator is intended to be templated:

template<typename ReturnType, typename ArgType1, typename ArgType2> operator ReturnType(*)(ArgType1, ArgType2) ( ) const { // implementation is unimportant here } 

As far as I know, I no longer cannot typedef such a type. This clearly makes things much more clumsy, but I hope that there is still a way.

4
  • try typedef'ing the return type: "typedef int (*ptr_t)(int,int);" then, return an object of type "operator ptr_t () const" Commented Jul 20, 2011 at 0:25
  • You are missing a colon. public: Commented Jul 20, 2011 at 0:30
  • are you trying to mimic boost::function? Commented Jul 20, 2011 at 0:37
  • @J T: I am doing something similar to boost::function but it has a very distinct behavior. I originally looked at using boost::function, but unfortunately I did not find it a suitable choice. Commented Jul 20, 2011 at 0:54

6 Answers 6

20

Since you must know:

(*operator int() const)(int, int) { return _funcPtr; } 

(Fixed. Again.)


Update: I've been informed by Johannes Schraub and Luc Danton that this syntax is in fact not valid, and that you really must use a typedef. Since you say that typedefs aren't an option, here's a helper class that can wrap your typedef:

template<typename R, typename A1, typename A2> struct MakeFunctionType { typedef R(*type)(A1, A2); }; template<typename R, typename A1, typename A2> operator typename MakeFunctionType<R, A1, A2>::type () const { // implementation is unimportant here } 
Sign up to request clarification or add additional context in comments.

11 Comments

this doesnt help with the template case he mentions
No, that was before the edit, but that should be straigth-forward to generalize to template<typename R, typename... Args> (*operator T() const)(Args...).
Thank you very much. Function pointer syntax can sometimes be quite confusing, especially in a scenario it seems that not many people use, and one in which typedefs are not applicable. Any chance I can get an explanation of why it looks that way? My idea is that operator int() const is the name of the function, so it is placed inside the parenthesis and preceded by an asterisk. Then, as usual for conversion operators, we drop the return type, since it is part of the name already. Is this the correct reason for the syntax?
The basic principle is that you always wrap the identifier of the final object in parentheses and append the arguments in another set of parentheses at the end: If the function signature is R(S, T), then a function pointer is R(*myfp)(S,T) (and the actual function type is R()(S,T)). Now we apply that thinking to operator A() const with A = R(*)(S,T) to get (*???)(S,T), where ??? = operator R() const. Think of passing from "type R" to "function returning type R".
Yeah, use a helper: <template typename R, typename... Arg> struct MakeMyFP { typedef R(*type)(Args...); };, then say <template typename R, typename... Args> operator typename MakeMyFP<R,Args...>::type () const.
|
4

Use a typedef. It's easier to read, anyway:

class Bar { public: typedef int (*fptr_t)(int, int); Bar(fptr_t funcPtr) : _funcPtr(funcPtr) { } operator fptr_t() const { return _funcPtr; } private: fptr_t _funcPtr; }; 

[edit]

For your template case I do not see how to use a typedef. @Kerrik gives the (messy) version of the syntax that should work.

4 Comments

Assuming the above works, is there a way without a typedef? Just curious; I agree the typedef makes much more sense.
Hi, thanks for the answer. You'll see that I edited my question, as I left out a small, yet super-important detail about my use of templates. Could I still harness the simplicity of a typedef in this case?
@J T - I think I posted my answer 15 minutes before you posted yours. Also 5 seconds before you posted your comment. (Wave your mouse over the times to see them in hours:minutes:seconds)
@JT and it can't happen that Nemo just answers this without reading your answer before? Why are you assuming he "steals" your answer? That's childish.
1

EDIT:

Since your class has a non template function pointer assigned at constuction:

private: int (*_funcPtr)(int, int); 

It is not at all possible to later convert that to a function pointer of any type.

I will therefore assume that you meant a template class member operator overload, not a class template member operator overload.

Template version:

template<typename ReturnType, typename ArgType1, typename ArgType2> class Bar { public: typedef ReturnType (*fptr_t)(ArgType1, ArgType2); operator fptr_t ( ArgType1 arg1, ArgType2 arg2 ) const { // implementation is unimportant here } //etc... }; 

Then used like this:

//create functor to some function called myfunc Bar::fptr_t func_ptr = Bar<int, int, int>(&myfunc); //call functor int i = func_ptr(1,2); 

2 Comments

This is a class template with a member function. It looks like he wants a real class with a member function template.
@J T: aschepler is exactly right. The same instance of Bar must be convertible to many different types of function pointers, so templating the class is not an option. And if anyone suggests it, I also cannot convert to templated functor type, it must be an actual function pointer.
1

If you want to make the code readable, you need to use a typedef. I don't even use functions pointers without typedef'ing them, the syntax is too horrid.

Goal:

template<typename ReturnType, typename ArgType1, typename ArgType2> operator ReturnType(*)(ArgType1, ArgType2) ( ) const { return 0; } 

Path:

// 1: helper structure template <typename R, typename A0, typename A1> struct helper { typedef R (*type)(A0,A1); }; // 2: operator template <typename R, typename A0, typename A1> operator typename helper<R, A0, A1>::type() const { return 0; } 

Check it out on ideone!

1 Comment

You're definitely right about the syntax being awful. It would've been nice to have a cleaner syntax, but I suppose we would probably end up using typedefs anyways.
1

In C++11, it is possible to use an alias template to convert to any function, bypassing the need for custom type trait structs.

class Bar { private: template<typename ReturnType, typename ArgType1, typename ArgType2> using funcptr = ReturnType(*)(ArgType1, ArgType2); public: template<typename ReturnType, typename ArgType1, typename ArgType2> operator funcptr<ReturnType, ArgType1, ArgType2> ( ) const; }; 

To limit this to just int(*)(int, int), we can use SFINAE or static_assert.

Comments

0

The following works in GCC:

template<typename ReturnType, typename ArgType1, typename ArgType2> operator decltype((ReturnType(*)(ArgType1, ArgType2)) nullptr)() const { // ... } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.