Извлечь возвращаемый тип функции, не вызывая ее (используя шаблоны?) - PullRequest
8 голосов
/ 05 января 2010

Я ищу способ C ++ для извлечения возвращаемого типа функции (без ее вызова).Я предполагаю, что это потребует некоторой магии шаблона.

float Foo();
int Bar();

magic_template<Foo>::type var1; // Here 'var1' should be of type 'float'
magic_template<Bar>::type var2; // and 'var2' should be of type 'int'

В настоящее время я изучаю, как можно реализовать magic_template, но пока не нашел решения.

Есть идеи?

Ответы [ 7 ]

7 голосов
/ 05 января 2010

Взгляните на библиотеку признаков boost , в частности шаблон function_traits предоставляет такую ​​функциональность из коробки. Если вы не можете использовать boost, просто загрузите код и прочитайте источники, чтобы понять, как это делается.

Обратите внимание, что функциональность основана на типах, а не на конкретных функциях, поэтому вам может потребоваться добавить туда дополнительный код.


После выполнения небольших тестов, это может быть не то, что вам действительно нужно, и если это «некоторый дополнительный код», будет нетривиальным. Проблема в том, что шаблон function_traits работает с сигнатурами функций, а не с фактическими указателями функций, поэтому проблема изменилась с «получить тип возвращаемого значения из указателя функции» на «получить сигнатуру из указателя функции», что, вероятно, является самым сложным часть там.

5 голосов
/ 05 января 2010

Foo и Bar - это функции, а не типы функций, поэтому вам нужно проделать дополнительную работу.

Вот решение, использующее комбинацию boost :: function_traits и BOOST_TYPEOF.

#include <boost/typeof/typeof.hpp>
#include <boost/type_traits.hpp>

float Foo();
int Bar();

int main()
{
  boost::function_traits<BOOST_TYPEOF(Foo)>::result_type f = 5.0f;
  boost::function_traits<BOOST_TYPEOF(Bar)>::result_type i = 1;
  return i;
}

Edit:

  • Это будет работать для функций любой арности до 10, что должно быть достаточно для наиболее разумного использования.
  • Это использование BOOST_TYPEOF работает на платформах, которые не предоставляют собственный тип typeof, поэтому он достаточно переносим.
5 голосов
/ 05 января 2010

Это сложно, потому что имена функций являются выражениями, а не типами - вам нужно что-то вроде gcc's typeof. Boost's TypeOf - это портативное решение, которое очень близко подходит.

Однако, если код можно организовать так, чтобы работа выполнялась в шаблоне функции, в который можно передать Foo или Bar, есть прямой ответ:

template <class R>
void test(R (*)())
{
  R var1;
}

int main()
{
  test(&Foo);
}
2 голосов
/ 05 января 2010

В C ++ 0x используйте decltype.

Чтобы обсудить проблемы и попытаться найти решение для более раннего стандарта C ++, см. Здесь:

Скотт Майерс «бросает вызов» (PDF) и Андрей Александреску пытается решить его

1 голос
/ 02 июля 2012

А вот и волшебство шаблона (не задействовано Boost):

template <typename ReturnType> class clFunc0
{
    typedef ReturnType ( *FuncPtr )();
public:
    typedef ReturnType Type;
};

template <typename ReturnType> inline clFunc0<ReturnType> ResultType( ReturnType ( *FuncPtr )() )
{
    return clFunc0<ReturnType>();
}

#define FUNC_TYPE( func_name ) decltype( ResultType( &func_name ) )::Type

int test()
{
    return 1;
}

int main()
{
    FUNC_TYPE( test ) Value = 1;

    return Value;
}

и скомпилировать через

gcc Test.cpp -std=gnu++0x
0 голосов
/ 05 января 2010

Как подсказал dribeas, вот решение, к которому я в итоге пришел:

float Foo();
int Bar();

template<typename T> Monkey(T) {
    boost::function_traits< boost::remove_pointer<T>::type >::result_type var1 = ...;
    // Now do something
}

Monkey(Foo);
Monkey(Bar);

Это не совсем та форма, к которой я стремился с помощью моего первоначального вопроса, но она достаточно близка для меня.

0 голосов
/ 05 января 2010

Попробуйте что-то вроде этого:

template<class T> struct magic_template
{};

template<class T> struct magic_template<T()>
{
    typedef T type;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...