gpt4 book ai didi

c++ - 强制执行参数评估顺序,同时保留表达式的生命周期

转载 作者:太空狗 更新时间:2023-10-29 20:52:40 26 4
gpt4 key购买 nike

给定一个宏FOO,用法如下:

std::string f1();
std::string f2();
FOO(f1().c_str(), f2().c_str());

注意:std::string 类型只是一个示例。 FOO 是通用的,可能不会假设任何类型。

这应该通过做类似的事情来保证 f1()f2() 的评估顺序:

#define FOO(e1, e2) \
do { \
auto v1 = e1; \
auto v2 = e2; \
foo(e1, e2); \
} while(0)

编辑:不幸的是 foo 也可以是模板。

不幸的是,这样 f1 返回的临时值被删除,c_strfoo 的调用变得无效。

有没有办法在保留所有临时生命周期的同时保证宏参数表达式求值的顺序?

当然有总体上更好的方法来解决这个问题,但我特别好奇是否有一种方法可以做到这一点而无需在大型代码库中推理该宏的每个用法。此外,我想避免处理特定类型(即不使用 strdup 保留 const char*)。

最佳答案

这在 C++17 中很简单,使用 std::apply :

#define FOO(...) std::apply(foo, decltype(std::forward_as_tuple(__VA_ARGS__)){__VA_ARGS__})

Example .

如果您使用的是 C++17 之前的标准库,则可以使用上述链接中的实现 std::apply 的方法。

如果foo 是函数模板或重载集,它不能直接传递给std::apply 所以它必须是wrapped in a polymorphic lambda :

#define FOO(...) std::apply( \
[](auto&&... args) -> decltype(auto) { return foo(std::forward<decltype(args)>(args)...); }, \
decltype(std::forward_as_tuple(__VA_ARGS__)){__VA_ARGS__})

之所以可行,是因为 {} 大括号内的求值顺序是严格从左到右的。我们使用 std::forward_as_tuple 来确定要传递给 apply 的元组的类型,但我们使用列表初始化语法构造它.

如果您使用带有类模板参数推导的 C++17 编译器,并且不需要担心左值引用,您可以进一步简化:

#define FOO(...) std::apply(foo, std::tuple{__VA_ARGS__})

不幸的是,因为解决方案(没有类模板参数推导)使用 decltype,所以如果参数涉及 lambda 表达式,它将不起作用。在这种情况下,我能看到让它工作的唯一方法是使用函数参数和函数体之间的顺序,将 FOO(e1, e2) 扩展为:

[&](auto&& p1) {
return [&](auto&& p2) {
return foo(std::forward<decltype(p1)>(p1), std::forward<decltype(p2)>(p2));
}(e2);
}(e1)

使用令人难以置信的 Boost.Preprocessor 这实际上是可能的图书馆:

#define FOO_IMPL_START(z,n,_) [&](auto&& p ## n) { return
#define FOO_IMPL_PARAM(z,n,_) std::forward<decltype(p ## n)>(p ## n)
#define FOO_IMPL_END(z,n,t) ; }(BOOST_PP_TUPLE_ELEM(n,t))
#define FOO_IMPL(n,t) \
BOOST_PP_REPEAT(n, FOO_IMPL_START, _) \
foo(BOOST_PP_ENUM(n, FOO_IMPL_PARAM, _)) \
BOOST_PP_REPEAT(n, FOO_IMPL_END, BOOST_PP_TUPLE_REVERSE(t))
#define FOO(...) (FOO_IMPL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__)))

Example .

关于c++ - 强制执行参数评估顺序,同时保留表达式的生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45610376/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com