views:

291

answers:

3

C# has generic function types such as Action<T> or Func<T,U,V,...>

With the advent of C++0x and the ability to have template typedef's and variadic template parameters, it seems this should be possible.

The obvious solution to me would be this:

template <typename T>
using Action<T> = void (*)(T);

however, this does not accommodate for functors or C++0x lambdas, and beyond that, does not compile with the error "expected unqualified-id before 'using'"

My next attempt was to perhaps use boost::function:

template <typename T>
using Action<T> = boost::function<void (T)>;

This doesn't compile either, for the same reason.

My only other idea would be STL style template arguments:

template <typename T, typename Action>
void foo(T value, Action f) {
    f(value);
}

But this doesn't provide a strongly typed solution, and is only relevant inside the templated function.

Now, I will be the first to admit that I am not the C++ wiz I prefer to think I am, so it's very possible there is an obvious solution I'm not seeing.

Is it possible to have C# style generic function types in C++?

+4  A: 

I think the syntax should be like this:

template <typename T>
using Action = void (*)(T);

I couldn't get that to compile either, though (g++ v4.3.2).

The general STL style function template is not strongly typed in the strictest sense, but it is type safe in the sense that the compiler will ensure that the template is only instantiated for types that fulfill all the requirements of the function. Specifically it will be a compiler error if the Action is not callable with one parameter of type T. This a very flexible approach since it doesn't matter if Action is instantiated to be a function or some class that implements operator().

The old non-C++0x workaround for the missing templated typedef would be to use a templated struct with a nested typedef:

template <typename T>
struct Action {
   typedef boost::function<void (T)> type;
};

template <typename T>
void foo(T value, typename Action<T>::type f) {
    f(value);
}
sth
+1  A: 

Gcc doesn't support yet template aliases (see here), and I'm not sure if variadic template alias are considered. I don't think other compilers support already this feature.

I will just use std::function or std::function instead of Action or Func.

Of course you can define variadic template classes Action or Func from std::function but I don't see the benefit.

Vicente Botet Escriba
+1  A: 

I don't think a generic function type is intuitive C++, because C++ templates work differently to generics.

The C++ way is to use function objects - anything which you can put () after and it makes sense to the compiler. This can be a function pointer, a class with operator(), and so on. This works because C++ templates are like fancy macros, and as long as the code makes sense with the types substituted you're OK.

C# generics don't work like that - they're more restrictive, probably in an effort to improve error messages (since getting C++ templates wrong is famously verbose in the output). I don't know too much about C# generics, but I think they rely on something which is more like callbacks, hence the usefulness of the function generics.

AshleysBrain