在 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>
类型(其中有多种实现)代表您所说的类型。不同之处在于它们携带 T
或 E
(T
== void
的特殊情况),其中携带 E
表示错误return 的消费者预期处理的值。
但所有这些都需要更改函数的实际 return 值。如果你死心塌地地使用像 void
、double
、int
等简单类型,那么你将不得不为任何 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 类型以及向函数定义中添加各种内容(属性、调用约定等)来破坏它。
此问题与 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>
类型(其中有多种实现)代表您所说的类型。不同之处在于它们携带 T
或 E
(T
== void
的特殊情况),其中携带 E
表示错误return 的消费者预期处理的值。
但所有这些都需要更改函数的实际 return 值。如果你死心塌地地使用像 void
、double
、int
等简单类型,那么你将不得不为任何 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 类型以及向函数定义中添加各种内容(属性、调用约定等)来破坏它。