确定函数返回类型的最简单方法

57

考虑一个非常简单但冗长的函数,例如:

int foo(int a, int b, int c, int d) {
    return 1;
}

// using ReturnTypeOfFoo = ???

如何在编译时最简单、最简洁地确定函数的返回类型(在此示例中为int,名称为ReturnTypeOfFoo),而不需要重复函数的参数类型(仅通过名称,因为已知该函数没有任何其他重载)?


根据编译器或者可用的支持库……,相当确定Concepts也有一些API可以在运行时或编译时推断出这些信息。 - Jay
1
也许是 decltype(foo)::result_type - Thomas Lang
可能是 https://zh.cppreference.com/w/cpp/types/result_of - bracco23
1
@ThomasLang 这是从哪里来的?decltype(foo)是一个没有result_type成员的函数,还是我漏掉了什么? - 463035818_is_not_a_number
@user463035818 你可能是对的,我指的是std::function类型的result_type成员。 - Thomas Lang
显示剩余3条评论
4个回答

75

在这里,您可以利用std::function,它将为函数返回类型提供一个别名。这需要C++17支持,因为它依赖于class template argument deduction,但它将适用于任何可调用类型:

using ReturnTypeOfFoo = decltype(std::function{foo})::result_type;

我们可以将这个变得更加通用一些,比如说

template<typename Callable>
using return_type_of_t = 
    typename decltype(std::function{std::declval<Callable>()})::result_type;

这样你就可以像使用它一样使用它了

int foo(int a, int b, int c, int d) {
    return 1;
}

auto bar = [](){ return 1; };

struct baz_ 
{ 
    double operator()(){ return 0; } 
} baz;

using ReturnTypeOfFoo = return_type_of_t<decltype(foo)>;
using ReturnTypeOfBar = return_type_of_t<decltype(bar)>;
using ReturnTypeOfBaz = return_type_of_t<decltype(baz)>;

这种技术只适用于函数没有被重载或者函数没有被定义多个operator()的情况下。


非常简洁!我可以确认这个一行代码也适用于模板方法,只要所有的模板参数都被指定。 - Cybran
7
在C++17中: using ReturnType = std::invoke_result_t<decltype(foo)>;意思是:定义一个名为ReturnType的类型别名,它使用std::invoke_result_t模板来获取调用foo函数后的返回值类型。 - tjklemz
@NathanOliver 如果你知道参数,就不会像链接中那样。 - apple apple
@苹果苹果 当然,但那时你必须要了解这些事情并提供这些内容。如果你想在不了解的情况下进行操作,那么就不能存在歧义。 - NathanOliver
@NathanOliver 没错,只是指出了限制。 - apple apple
显示剩余4条评论

27

最简单和简明的可能是:

template <typename R, typename... Args>
R return_type_of(R(*)(Args...));

using ReturnTypeOfFoo = decltype(return_type_of(foo));

请注意,这对于函数对象或成员函数指针不起作用。仅适用于未经过载或模板化的函数或noexcept函数。

但是,如果需要支持所有这些情况,可以通过添加更多的return_type_of重载来实现。


19

我不知道是否这是最简单的方法(如果你可以使用C++17,肯定不是:参见NathanOliver的答案),但是... 声明一个函数如下:

template <typename R, typename ... Args>
R getRetType (R(*)(Args...));

而且使用 decltype()

using ReturnTypeOfFoo = decltype( getRetType(&foo) );

注意,getRetType()只被声明而不被定义,因为它只在decltype()中被调用,因此只有返回的类型是相关的。


-1
多年以后,您可能会对我的解决方案这里(生产级别,完全记录)感兴趣。它是其他一些想法的完整实现,您在这里看到了一些响应(请参见Barry和max66的响应)。但是,您可以针对函数的几乎任何内容进行定位(在C++本身的限制范围内),而不仅仅是返回类型。
下载代码,将“TypeTraits.h”和“CompilerVersions.h”添加到您的项目中,然后执行以下操作(请注意,您不必显式#include“CompilerVersions.h”,它已自动包含在“TypeTraits.h”中)。
#include "TypeTraits.h"
using namespace StdExt; // Everything's in this namespace
using ReturnTypeOfFoo = ReturnType_t<decltype(foo)>;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接