Как можно вывести тип аргумента функции в С++?

Имея определение функции:

void f(int) { }

Я хочу определить:

int a;

но если определение функции изменится на:

void f(double) { }

определение переменной должно быть:

double a;

то есть тип "a" должен быть тем же самым из первого аргумента функции "f". Мне нужно что-то вроде следующего:

decltype_of_argument<f, 0> a;

Возможно ли это в С++?

Ответы

Ответ 1

Вы можете получить тип путем метапрограммирования шаблонов:

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;
}

В зависимости от того, где вы хотите его использовать, вам нужно будет специализировать этот шаблон litte для других вызываемых объектов, таких как функции-члены-члены, функции с большим количеством аргументов, функторы и т.д. В библиотеках Boost есть более изощренные подходы, см., например, fooobar.com/questions/387125/...

Предостережение: все эти утилиты работают только в том случае, если имя функции/вызываемого однозначно отображается на одну подпись функции. Если функция перегружена или если функтор имеет более одного operator(), то правильный оператор функции/должен быть выбран путем явного нажатия на правую подпись, что делает поиск части сигнатуры через шаблон довольно бесполезным. Это также относится к шаблонам определенным образом, хотя получение подписи явно разделяемого вызова может быть полезным, например:

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 use here
ArgType<1, decltype(&f<double>)> //double - here it useless...

Ответ 2

Использовать шаблон?

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

Ответ 3

Это зависит от того, что вы хотите сделать, где эта переменная будет использоваться. Если это функция, шаблон может быть хорошим выбором:

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

Альтернативно, если вы находитесь вне функции и имеете требование действительно знать это, вы можете использовать Boost.TypeTraits, то есть function_traits<void (int)>::arg1_type даст int

Ответ 4

Один из подходов - использовать typedef для типа параметра функции. Например

typedef int TParm;

void f( TParm );

TParm a;

Вы можете выбрать любое имя для этого типа. Например parm_t и т.д. Важно, чтобы не было столкновения имен.

В этом случае вам нужно будет изменить только typedef, если вы хотите изменить тип параметра.

Или, если ваш компилятор поддерживает псевдонимы, вы также можете написать

using TParm = int;

void f( TParm );

TParm a;

Также вы можете обернуть функцию в пространстве имен или классе.:) Например

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

//...

IFunction::parm_t a;
IFunction::f( a );

Ответ 5

Как создать функцию шаблона?

template <typename T>
void f(T t);