当从宏传递到函数时,避免传递 void 表达式
Avoid passing void expression, when pass from macro to function
我想写一个调试宏,在出现错误时打印调用函数的名称。问题是一些函数 return 值,我想 return 从宏返回任何值。
这是我的尝试:
#define check(expr) _check_expr(#expr, expr)
extern bool check_for_error();
template <typename T> inline T _check_expr(const char *str, T value)
{
if (check_for_error()) {
fprintf(stderr, "Failure: %s\n", str);
}
return value;
}
我遇到的问题是有时 T = void
并且编译器不会让我将 void
类型的表达式传递给函数:
../src/render.cc: In constructor ‘render::impl::impl()’:
../src/render.cc:34:20: error: invalid use of void expression
34 | check(glDisable(GL_DEPTH_TEST));
我无法重新定义要在 check
宏或 check_for_error
函数下调用的函数,它们在我的程序之外。此外,需要在计算表达式后检查错误。
在C++中有解决这个问题的好方法吗?
类似于:“如果此表达式的 decltype 为空,则生成此代码,否则生成该代码”。
- 初衷
如果您总是需要宏 #define check(expr) _check_expr(#expr, expr)
,则无法避免传递 void
。宏没有重载或调度机制。
- 更新想法
非常感谢@Daniel Jour 提出了将表达式包装到 lambda 中传递的想法,我在 C++11
中提出了一个实现(我更喜欢 C++11
,因为我不太熟悉C++17
作为@Daniel Jour),灵感来自@Daniel Jour 的回答:
#include <iostream>
#include <type_traits>
#define check(expr) _check_expr(#expr, [&]() { return expr; })
//bool check_for_error() { return true; }
extern bool check_for_error();
void check_(const char *str) {
if (check_for_error()) {
std::cerr << "Failure in: " << str << std::endl;
}
}
template <typename Fn>
using returnType = typename std::result_of<Fn()>::type;
template <typename Fn, typename = typename std::enable_if<
!std::is_void<returnType<Fn>>::value>::type>
inline auto _check_expr(const char *str, Fn fn) ->
typename std::result_of<Fn()>::type {
auto v = fn();
check_(str);
return v;
}
template <typename Fn, typename = typename std::enable_if<
std::is_void<returnType<Fn>>::value>::type>
inline void _check_expr(const char *str, Fn fn) {
fn();
check_(str);
}
A void function can return a void expression。这也适用于 lambda:
#define check(expr) _check_expr(#expr, [&] () { return expr; })
extern bool check_for_error();
template <typename Fn>
inline auto _check_expr(const char *str, Fn fn)
{
auto check_ = [str]() {
if (check_for_error()) {
fprintf(stderr, "Failure: %s\n", str);
}
};
if constexpr (std::is_same_v<std::invoke_result_t<Fn>, void>) {
fn();
check_();
} else {
auto v = fn();
check_();
return v;
}
}
可能有更好的解决方案,但这行得通。此外,这至少需要当前形式的 C++17,但可能可以向后移植到 C++14 甚至 C++11。
我想写一个调试宏,在出现错误时打印调用函数的名称。问题是一些函数 return 值,我想 return 从宏返回任何值。
这是我的尝试:
#define check(expr) _check_expr(#expr, expr)
extern bool check_for_error();
template <typename T> inline T _check_expr(const char *str, T value)
{
if (check_for_error()) {
fprintf(stderr, "Failure: %s\n", str);
}
return value;
}
我遇到的问题是有时 T = void
并且编译器不会让我将 void
类型的表达式传递给函数:
../src/render.cc: In constructor ‘render::impl::impl()’:
../src/render.cc:34:20: error: invalid use of void expression
34 | check(glDisable(GL_DEPTH_TEST));
我无法重新定义要在 check
宏或 check_for_error
函数下调用的函数,它们在我的程序之外。此外,需要在计算表达式后检查错误。
在C++中有解决这个问题的好方法吗?
类似于:“如果此表达式的 decltype 为空,则生成此代码,否则生成该代码”。
- 初衷
如果您总是需要宏 #define check(expr) _check_expr(#expr, expr)
,则无法避免传递 void
。宏没有重载或调度机制。
- 更新想法
非常感谢@Daniel Jour 提出了将表达式包装到 lambda 中传递的想法,我在 C++11
中提出了一个实现(我更喜欢 C++11
,因为我不太熟悉C++17
作为@Daniel Jour),灵感来自@Daniel Jour 的回答:
#include <iostream>
#include <type_traits>
#define check(expr) _check_expr(#expr, [&]() { return expr; })
//bool check_for_error() { return true; }
extern bool check_for_error();
void check_(const char *str) {
if (check_for_error()) {
std::cerr << "Failure in: " << str << std::endl;
}
}
template <typename Fn>
using returnType = typename std::result_of<Fn()>::type;
template <typename Fn, typename = typename std::enable_if<
!std::is_void<returnType<Fn>>::value>::type>
inline auto _check_expr(const char *str, Fn fn) ->
typename std::result_of<Fn()>::type {
auto v = fn();
check_(str);
return v;
}
template <typename Fn, typename = typename std::enable_if<
std::is_void<returnType<Fn>>::value>::type>
inline void _check_expr(const char *str, Fn fn) {
fn();
check_(str);
}
A void function can return a void expression。这也适用于 lambda:
#define check(expr) _check_expr(#expr, [&] () { return expr; })
extern bool check_for_error();
template <typename Fn>
inline auto _check_expr(const char *str, Fn fn)
{
auto check_ = [str]() {
if (check_for_error()) {
fprintf(stderr, "Failure: %s\n", str);
}
};
if constexpr (std::is_same_v<std::invoke_result_t<Fn>, void>) {
fn();
check_();
} else {
auto v = fn();
check_();
return v;
}
}
可能有更好的解决方案,但这行得通。此外,这至少需要当前形式的 C++17,但可能可以向后移植到 C++14 甚至 C++11。