提取函数的返回类型而不调用它(使用模板?)

时间:2010-01-05 11:51:21

标签: c++ templates c++11 metaprogramming

我在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 个答案:

答案 0 :(得分:7)

看一下boost type traits库,特别是function_traits模板提供了开箱即用的功能。如果你不能使用boost,只需下载代码并阅读源代码,以便了解它是如何完成的。

请注意,该功能基于类型,而不是具体功能,因此您可能需要在那里添加一些额外的代码。


在做了一些小测试之后,这可能不是你真正需要的,如果它是'一些额外的代码'将是非平凡的。问题是function_traits模板适用于函数签名而不是实际的函数指针,因此问题已经从'从函数指针获取返回类型'变为'从函数指针获取签名'这可能是那里最难的部分。

答案 1 :(得分:5)

这很棘手,因为函数名称的表达式不是类型 - 你需要像gcc的typeof这样的东西。 Boost的TypeOf是一种非常接近的便携式解决方案。

但是,如果可以对代码进行组织,以便在可以传递FooBar的函数模板内完成工作,那么可以直截了当地回答:

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

int main()
{
  test(&Foo);
}

答案 2 :(得分:5)

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

编辑:

  • 这适用于任何高达10的arity的功能,这应该足以满足最明智的用途。
  • 这种BOOST_TYPEOF的使用适用于不提供原生类型的平台,因此它具有合理的便携性。

答案 3 :(得分:2)

在C ++ 0x中,使用decltype

有关问题的讨论并尝试构建早期C ++标准的解决方案,请参见此处:

Scott Myers "challenge"(PDF)和Andrei Alexandrescu trying to solve it

答案 4 :(得分:1)

模板魔术(不涉及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

答案 5 :(得分:0)

正如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);

这不是我原来的问题所针对的形式,但它对我来说足够接近。

答案 6 :(得分:-1)

尝试这样的事情:

template<class T> struct magic_template
{};

template<class T> struct magic_template<T()>
{
    typedef T type;
};