20

Having the function definition:

void f(int) { }

I want to define:

int a;

but if the function definition changes to:

void f(double) { }

the variable definition must become:

double a;

that is, the type of "a" must be the same of the first argument of the "f" function. I need something like the following:

decltype_of_argument<f, 0> a;

Is it possible in C++?

user3459257
  • 320
  • 2
  • 7

4 Answers4

26

You can get the type by template metaprogramming:

template <class F> struct ArgType;

template <class R, class T> 
struct ArgType<R(*)(T)> {
  typedef T type;
}; 

void f(int) {}

#include <type_traits>
#include <iostream>

int main() {

  // To prove
  std::cout << std::is_same< ArgType<decltype(&f)>::type, int >::value << '\n';

  // To use
  ArgType<decltype(&f)>::type a;
}

Depending on where you want to use it you'd need to specialize this litte template for other callable entities such as member function poitners, functions with more arguments, functors etc. There are more sophisitcated approaches in the Boost libraries, see e.g. https://stackoverflow.com/a/15645459/1838266

Caveat: all these utilities work only if the name of the function/callable is unambiguously mapped to one single function signature. If a function is overloaded or if a functor has more than one operator(), the right function/operator has to be picked by explicitly casting to the right signature, which makes finding out part of the signature via the template pretty useless. This applies in a certain way to templates as well, although getting the signature of an explicitly secialized callable might still be useful, e.g.:

template <unsigned N, class F> struct ArgType; //somewhat more sophisitcated 

template <class T> void f(int, T);

ArgType<0, decltype(&f<double>)> //int    - ArgType has it's use here
ArgType<1, decltype(&f<double>)> //double - here it's useless...
uckelman
  • 25,298
  • 8
  • 64
  • 82
Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
  • +1 Excellent, This is the answer! I was trying to write this but you was faster. – masoud Mar 25 '14 at 11:09
  • Note: if `f` is overloaded it will be `ArgType(&f))>::type a;` which is getting less useful, obviously... – Matthieu M. Mar 25 '14 at 12:39
  • @MatthieuM. thanks for the hint, galop1n's and my comments on the question mention that issue, I added it for clarity to the answer. – Arne Mertz Mar 25 '14 at 12:49
  • 1
    Since C++20, it is also possible to infer function argument types [using `auto`](https://stackoverflow.com/questions/29944985/is-there-a-way-to-pass-auto-as-an-argument-in-c/60355539#60355539). – Anderson Green Mar 14 '22 at 20:44
3

One of approaches is to use typedef for the type of the function parameter. For example

typedef int TParm;

void f( TParm );

TParm a;

You can select any name for the type. For example parm_t and so on. It is important that there will not be a name collision.

In this case you will need to change only the typedef if you want to change the type of the parameter.

Or if your compiler supports aliases you can also write

using TParm = int;

void f( TParm );

TParm a;

Also you can wrap the function in a namespace or class.:) For example

struct IFunction
{
   typedef int parm_t;
   static void f( parm_t = parm_t() ) {}
};

//...

IFunction::parm_t a;
IFunction::f( a );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • This is probably the nearest to what the OP required, but I think it would be better to think about the need of this... I mean double and int can be cast if needed. – Theolodis Mar 25 '14 at 10:55
3

It depends on what you want to do, where that variable shall be used. If it is in the function a template might be a good choice:

template<typename T>
void foo(T ) {
    T a;
}

Alternatively if you are outside the function and have the requirement to really know this you can use Boost.TypeTraits, i.e. function_traits<void (int)>::arg1_type will give int

johannes
  • 15,807
  • 3
  • 44
  • 57
  • 1
    Using `function_traits::arg1_type` to get `int`?! Why doesn't he just write `int` ?! – masoud Mar 25 '14 at 11:02
  • 1
    @MM. since this is the simple form. In reality you either have a typedef or a function pointer maybe even to a template where it isn't so obvious. – johannes Mar 25 '14 at 11:05
-1

How about making the template function?

template <typename T>
void f(T t);
Argenet
  • 379
  • 2
  • 9