滥用逗号运算符来库里函数参数
Abusing comma operator to curry function arguments
在某些语言中,调用函数时可以省略括号。
frobnicate foo, bar, baz, qux
让我们看看我们是否可以将其或类似的东西带入C++。这几乎肯定意味着滥用逗号运算符,但是,据我所知,没有办法扩展任意类型以使用重载的逗号运算符。因此,像代理咖喱类型这样的东西可以工作。
comma_curry(frobnicate), foo, bar, baz, qux;
comma_curry
(我不擅长想出名字)可能是某种增量库里尔,其逗号运算符一次接受一个参数。理想情况下,我希望它具有完美的转发语义,这样它与简单地直接调用frobnicate
没有什么不同。
frobnicate(foo, bar, baz, qux);
特别是如果某些参数本身是函数调用,则可能会返回 prvalues。
frobnicate(foo(), bar, baz(), qux);
我已经尝试并提出了一个不起作用的示例,使用从另一篇文章复制的一些帮助程序代码。 有人有一些好或更好的想法吗?
当然,所有这些对于普通函数参数来说都是微不足道的。
我不建议使用逗号运算符,除非用于学习和玩具示例。不要将其放在生产代码中。
但是使用逗号运算符对于增量和重新库里也很有趣。下面是一个工作示例:
template<typename F, typename... Curry>
struct comma_curry {
template<typename... C>
explicit comma_curry(F function, C&&... c) noexcept :
function(std::move(function)), curry{std::forward<C>(c)...} {}
template<typename T>
friend auto operator,(comma_curry&& self, T&& arg) -> comma_curry<F, Curry..., std::decay_t<T>> {
return std::apply([&](auto&&... curry) {
return comma_curry<F, Curry..., std::decay_t<T>>(std::move(self.function), std::forward<decltype(curry)>(curry)..., std::forward<T>(arg));
}, std::move(self.curry));
}
template<typename... Args>
auto operator()(Args&&... args) const& -> decltype(auto) {
return std::apply([&](auto&&... curry) -> decltype(auto) {
return function(std::forward<decltype(curry)>(curry)..., std::forward<Args>(args)...);
}, curry);
}
template<typename... Args>
auto operator()(Args&&... args) && -> decltype(auto) {
return std::apply([&](auto&&... curry) -> decltype(auto) {
return std::move(function)(std::forward<decltype(curry)>(curry)..., std::forward<Args>(args)...);
}, std::move(curry));
}
private:
// [[no_unique_address]]
F function;
// [[no_unique_address]]
std::tuple<Curry...> curry;
};
它支持通过std::ref
的柯里引用,并支持柯里仅移动类型。
它可以像这样使用:
int main() {
auto function = [](int& i, double, std::unique_ptr<int>, std::tuple<int>) {
std::cout << "Called! i value: " << i << std::endl;
};
int number = 1;
// Reference arguments are sent using std::ref
auto curried = (comma_curry(function), std::ref(number), 1.5);
curried(std::make_unique<int>(), std::tuple{1});
number = 42;
auto recurried = (std::move(curried), std::make_unique<int>(), std::tuple{1});
// We curried a std::unique_ptr, our function is a one time call
// Since it's a one time call and destroy itself in the calling,
// it must be moved
std::move(recurried)();
}
现场示例
这是我的想法的要点。请注意,它仅适用于单参数函数,但可以轻松扩展为咖喱。我使用标签类型来确保选择正确的重载:
#include <functional>
#include <type_traits>
#include <utility>
void print_thing(int a) {
}
struct go_t{} go;
template<class F>
auto operator,(go_t, F f) {
return [a=std::move(f)](const auto& b) {
return a(b);
};
}
template<class T>
auto operator,(const std::function<void(T)>& f, T&& t) {
return f(std::forward<T>(t));
}
int main() {
// Make this happen!
(go, print_thing, 42);
}
相关文章:
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- C++中的高效循环缓冲区,它将被传递给C样式数组函数参数
- 当从函数参数中的临时值调用复制构造函数时
- 如何从"decltype()"获取函数参数的数量<funtion>?
- 如何将lambda作为模板类的成员函数参数
- 模板参数推导失败,函数参数/参数不匹配
- 如何在C++中将迭代器作为函数参数传递
- 将函数参数"const char*"转换为"std::string_view"是
- C++ 如何将数组值解压缩为函数参数
- 主函数参数的属性
- 具有两个间接寻址运算符 (C++) 的函数参数的用途
- "Warning: Comma within array index expression"但逗号分隔函数参数
- 如何定义在用作函数参数时工作的类模板的转换
- 将函数参数完美转发到函数指针:按值传递呢?
- 为什么我不能将引用作为 std::async 的函数参数传递
- 什么..(省略号)作为函数原型中唯一的函数参数,C++?
- 是否可以就地构造一个固定大小的数组作为函数参数?
- 接受模板作为函数参数
- 将成员函数作为构造函数参数调用时出错 "Variable is not a type name"
- Arduino 函数参数