在 C++ 中获取 return 类型的当前函数

Get return type of current function in C++

此问题与 Get return type of function in macro (C++) 类似,但已有 10 年历史且未得到解答。接受任何其他解决方案。

我想创建一个断言宏,如果条件不满足,它只从函数中获取 returns,例如:

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

如果包含函数 return 无效,这将不起作用,但我不想创建 2 个宏。我希望能够 add/remove return 值而不更改代码。我的想法是创建一个辅助函数:

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

现在宏可以像这样工作:

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

但我需要当前函数的 return 类型 T 而不必调用 ASSERT(i != nullptr, double) 之类的东西,因为这样我就可以简单地使用 2 个宏。此外,像 __func__ 和 std::source_location 这样的宏只是字符串。

如果您不知道函数的 return 类型,则没有表达式 X 其中语句 return X;void- returning 函数和一个 return 任意类型的函数。

可以创建一个特殊的用户定义模板类型,其中 return X; 对多种类型都有效。例如 return std::nullopt; 对函数 returning any optional<T> 总是有效的。您可以从像 nullopt 这样的对象创建具有类似隐式转换属性的类似类型,一个具有允许 void 类型被“携带”的特化(尽管不允许 std::optional<void>您可以使用无状态类型作为 void).

的等价物

当然,这现在要求调用者从您的类型中提取 returned 值(如果有)。这也意味着它必须检查一个值是否被 return 编辑。

expected<T, E> 类型(其中有多种实现)代表您所说的类型。不同之处在于它们携带 TET == void 的特殊情况),其中携带 E 表示错误return 的消费者预期处理的值。

但所有这些都需要更改函数的实际 return 值。如果你死心塌地地使用像 voiddoubleint 等简单类型,那么你将不得不为任何 return 使用不同的宏你在做。

这可以使用 __PRETTY_FUNCTION__ (GCC, Clang) /__FUNCSIG__ (MSVC),一个非标准的扩展名,给你当前函数的名字,包括 return类型。

你可以在编译时分析字符串,看看它是否有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);
}

这需要进行更多测试以确保您不会通过尾随 return 类型以及向函数定义中添加各种内容(属性、调用约定等)来破坏它。