3

I would like to simplify foo by using a typedef to represent the type for the ptr argument.

#include <iostream>

template <unsigned N>
int foo (int (*ptr) (const char (*)[N])) {
    char good[N] = "good";
    return ptr(&good);
}

int bar (const char (*x)[5]) {
    std::cout << *x << "\n";
    return 0;
}

int main ()
{
    return foo(bar);
}

I would like to write foo() to be more like this:

template <unsigned N>
int foo (FUNCTION_TYPE *ptr) {
    char good[N] = "good";
    return ptr(&good);
}

I tried using a traits like helper class, but that failed. Is there a proper way to create a typedef for FUNCTION_TYPE?

Community
  • 1
  • 1
jxh
  • 69,070
  • 8
  • 110
  • 193

4 Answers4

3

In C++11, you can get the rough equivalent of a template typedef by using the using keyword. This still allows N to be deduced from the argument:

template <unsigned N>
using fooP = int (*) (const char (*)[N]);

template <unsigned N>
int foo (fooP<N> ptr) {
  return ptr(0);
}

int bar(const char (*p)[2]) {
  return 0;
}

int main() {
  return foo(bar);
}
1

Yes, you can use a default template argument:

template <unsigned N, typename T = int (*) (const char (*)[N])>
int foo (T ptr);

Here is a compiling demo.

Another option is to use std::function:

#include <functional>
#include <string>

int foo(std::function<int(std::string)>& ptr)
{
    // ...
}
David G
  • 94,763
  • 41
  • 167
  • 253
  • That's probably a bad use case for default template arguments. It makes `int bar(int (const char(*)[3])); foo<2>(bar);` compile without any issues. –  Jun 10 '13 at 22:03
  • @hvd [Um..no it doesn't...](http://coliru.stacked-crooked.com/view?id=8385c44c894eee4c747bd070f35a136e-41475e255c735859f2b181fd0d057a6f) – David G Jun 10 '13 at 22:05
  • Your compiling demo using `foo<5>(bar)`. I want template argument deduction to work. – jxh Jun 10 '13 at 22:05
  • @0x499602D2 Try simply `return 0;` in `foo`. It compiles or doesn't depending on whether the instantiation succeeds. In your example, it fails, but in general, it could very well succeed. –  Jun 10 '13 at 22:09
  • @jxh You won't get type deduction with this, but why not use `std::function` instead? – David G Jun 10 '13 at 22:12
  • I want foo() to pass a pointer to the right array size to the passed in function. See the updated post. Consider the N parameter and the body of foo() to be immutable. – jxh Jun 10 '13 at 22:13
  • @jxh Then I wouldn't know how to do this. See the other answers, they seem to have got it. :) – David G Jun 10 '13 at 22:15
1

Actually you can just make it template

template<unsigned N, typename Func) 
int foo(Func func){ return func("good"); }

int bar(const std::string& str){ return str == "good"; }

int main(){    const int r = foo(bar); }

That way not only are you not limited to passing regular functions but you can also pass in functors

Community
  • 1
  • 1
dchhetri
  • 6,926
  • 4
  • 43
  • 56
  • I am aware of this, but I want `foo()` to pass a pointer to the right array size to the passed in function. See the updated post. Consider the `N` parameter and the body of `foo()` to be immutable. – jxh Jun 10 '13 at 22:11
1

So your basic problem is that dependent types are not inferred in a function call.

Assuming you want to deduce the value N while doing away with that mess, what you need is the ability to map from the function type to the value N.

template<typename Func>
struct get_N {};
template<unsigned int N>
struct get_N< int( const char(*)[N] ) > {
  typedef std::integral_constant< unsigned int, N > type;
};
template<typename Func>
using getN = typename get_N<Func>::type;

once you have this, you can use it in the template type arguments:

template <typename Func, typename Nt = getN<Func>>
int foo (Func* ptr) {
  constexpr N = Nt::value;
  return ptr(&"good");
}

and we have access to the N within foo, and the only things (barring some fancy footwork) that can match foo are things that get_N understands (via SFINAE).

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • This is a nifty workaround. I believe `integral_constant` is C++11. But some version of your solution should be portable to C++-03, right? – jxh Jun 10 '13 at 22:19
  • Yes. Integral constant is a really simple one, it just makes `value` equal to the value passed in (it also does typing, but you can just do an `enum` or whatever). – Yakk - Adam Nevraumont Jun 10 '13 at 22:43