简体   繁体   English

在 C++ 中获取当前 function 的返回类型

[英]Get return type of current function in C++

This question is similar to Get return type of function in macro (C++) but it is 10 Years old and is not answered.这个问题类似于Get return type of function in macro (C++)但它已有 10 年历史,没有得到回答。 Any other solution would be accepted.任何其他解决方案都将被接受。

I want to create an assert macro that only returns from the function if the condition isn't met, Like:我想创建一个断言宏,如果不满足条件,它只从 function 返回,例如:

#define ASSERT(X) if(!(X)) return {};

This doesn't work if the containing function returns void, but I don't want to create 2 macros.如果包含 function 返回 void,这将不起作用,但我不想创建 2 个宏。 I want to be able to add/remove return values without changing the code.我希望能够在不更改代码的情况下添加/删除返回值。 My idea is to create a helper function:我的想法是创建一个助手 function:

template<class T>
T re(){
    if constexpr( std::is_same<T, void>::value ){
        return;
    }
    else if constexpr( ! std::is_same<T, void>::value ){
        return {};
    }
}

Now the macro could work like:现在宏可以像这样工作:

double f(int *i){
    if(i == nullptr){
        typedef std::invoke_result<decltype(&f),int>::type T; // only works for this function
        return re<T>();
    }
    return 1.0;
}

But I require the return type T of the current function without having to call something like ASSERT(i,= nullptr, double) because then I could simply use 2 macros.但是我需要当前 function 的返回类型 T 而不必调用诸如ASSERT(i,= nullptr, double)之类的东西,因为这样我就可以简单地使用 2 个宏。 Also, macros like __func__ and std::source_location are only strings.此外,像 __func__ 和 std::source_location 这样的宏只是字符串。

There is no expression X where the statement return X;语句return X; X will be valid for both a void returning function and a function that returns an arbitrary type.对于返回 function 的void和返回任意类型的 function 均有效。

One can create a special user-defined template type where return X;可以创建一种特殊的用户定义模板类型,其中return X; will be valid for a variety of types.将适用于多种类型。 For example return std::nullopt;例如return std::nullopt; is always valid for a function returning any optional<T> .对于返回任何optional<T>的 function 始终有效。 You can create a similar type with similar implicit conversion properties from an object like nullopt , one with a specialization to allow a void type to be "carried" ( std::optional<void> is not allowed, though you could use a stateless type as an equivalent to void ).您可以从 object (如nullopt )创建具有类似隐式转换属性的类似类型,该类型具有允许“携带” void类型的特化( std::optional<void>是不允许的,尽管您可以使用无状态类型作为void的等价物)。

Of course, this now requires the caller to extract the returned value (if any) from your type.当然,这现在需要调用者从您的类型中提取返回值(如果有的话)。 This also means that it has to check to see if a value was returned or not.这也意味着它必须检查是否返回了值。

The expected<T, E> type (of which there are several implementations) represents a type like what you're talking about. expected<T, E>类型(其中有几种实现)表示您正在谈论的类型。 The difference is that they carry either a T or E (with a special case for T == void ), where carrying an E represents an error value that the consumer of the return is expected to handle.不同之处在于它们带有TET == void的特殊情况),其中带有E表示期望返回的消费者处理的错误值。

But all these require changing the function's actual return value.但所有这些都需要更改函数的实际返回值。 If you're dead-set on using simple types like void , double , int , etc, then you're going to have to have different macros for whatever return you're doing.如果您对使用简单类型(如voiddoubleint等)很执着,那么无论您正在做什么返回,您都必须使用不同的宏。

This is possible using __PRETTY_FUNCTION__ (GCC, Clang) / __FUNCSIG__ (MSVC), a non-standard extension that gives you the name of the current function, including the return type.这可以使用__PRETTY_FUNCTION__ (GCC, Clang) / __FUNCSIG__ (MSVC) 来实现,这是一个非标准扩展,它为您提供当前 function 的名称,包括返回类型。

You can analyze the string at compile-time to see if it has void in it or not:您可以在编译时分析字符串以查看它是否包含void

#include <string_view>

struct AnyType
{
    template <typename T>
    operator T()
    {
        return {};
    }
};

template <bool IsVoid>
auto foo()
{
    if constexpr (IsVoid)
        return;
    else
        return AnyType{};
}

#ifndef _MSC_VER
#define FUNCNAME __PRETTY_FUNCTION__
#else
#define FUNCNAME __FUNCSIG__
#endif

#define ASSERT(x) if (!bool(x)) return foo<std::string_view(FUNCNAME).starts_with("void ")>()

void x()
{
    ASSERT(0);
}

int y()
{
    ASSERT(0);
}

This needs more testing to make sure you can't break it with trailing return types, and by adding various stuff to function definition (attributes, calling conventions, etc).这需要更多的测试,以确保您不能用尾随返回类型破坏它,并通过向 function 定义(属性、调用约定等)添加各种内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM