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.

Community
  • 1
  • 1
Ken Wayne VanderLinde
  • 18,915
  • 3
  • 47
  • 72

6 Answers6

19

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
}
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • this doesnt help with the template case he mentions – J T Jul 20 '11 at 00:54
  • 1
    No, that was before the edit, but that should be straigth-forward to generalize to `template (*operator T() const)(Args...)`. – Kerrek SB Jul 20 '11 at 01:00
  • 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? – Ken Wayne VanderLinde Jul 20 '11 at 01:00
  • 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`". – Kerrek SB Jul 20 '11 at 01:04
  • Oh, and it did help with producing the template version, since that particular use case was intended to help in defining a type which is similar (though distinctly different from) the `nullptr_t` type. So I was actually able to just return 0. My main concern was find the syntax for such an operator when I couldn't rely on using a typedef. And thank you also for the explanation for writing function pointers in general. – Ken Wayne VanderLinde Jul 20 '11 at 01:06
  • Hm, I doubt there's ever a situation where you cannot use a typedef, and a typedef would surely make things more palatable, but if you find the direct syntax useful, by all means knock yourself out :-) – Kerrek SB Jul 20 '11 at 01:07
  • @Kerrek: Well, I'm not sure if I could use a typedef along with template parameters, as the parameters must be immediately used to define the function's return type. I don't see a way to squeeze a typedef in there. – Ken Wayne VanderLinde Jul 20 '11 at 01:09
  • 1
    Yeah, use a helper: ` – Kerrek SB Jul 20 '11 at 01:12
  • @KerrekSB: Stop doubting, **this** is the situation where you cannot use a template helper (typedef templates don't exist). With template helper, the compiler can't deduce the template parameters unless the caller uses the same template to declare the expected type, which they usually won't. – Jan Hudec Dec 14 '11 at 13:08
  • @KerrekSB: In fact it might be possible to use the new C++11 type alias, which can be templated, but I only have VC++9.0 and G++ 4.5.3 and type aliases are only supported in G++ 4.7 and I am not even sure about VC++10. – Jan Hudec Dec 14 '11 at 13:10
  • @JanHudec: You're right, this looks like it's a non-deducible context (which means that even template-using declarations don't help.) Typedef it is then. – Kerrek SB Dec 14 '11 at 13:25
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.

Nemo
  • 70,042
  • 10
  • 116
  • 153
  • Assuming the above works, is there a way without a typedef? Just curious; I agree the typedef makes much more sense. – Chris Jul 20 '11 at 00:27
  • 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? – Ken Wayne VanderLinde Jul 20 '11 at 00:32
  • @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) – Nemo Jul 20 '11 at 01:02
  • @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. – Johannes Schaub - litb Jul 22 '11 at 22:24
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.

llf
  • 610
  • 10
  • 11
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); 
J T
  • 4,946
  • 5
  • 28
  • 38
  • This is a class template with a member function. It looks like he wants a real class with a member function template. – aschepler Jul 20 '11 at 00:44
  • @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. – Ken Wayne VanderLinde Jul 20 '11 at 00:48
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!

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 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. – Ken Wayne VanderLinde Jul 20 '11 at 23:05
0

The following works in GCC:

template<typename ReturnType, typename ArgType1, typename ArgType2>
operator decltype((ReturnType(*)(ArgType1, ArgType2)) nullptr)() const
{
    // ...
}
Vladimir Reshetnikov
  • 11,750
  • 4
  • 30
  • 51