运算符旁边的参数解包
Parameter unpacking next to operator
我正在编写一个小的可变求和函数(使用 c++20,但我的问题将与 c++17 语法相同)。我想让下面的代码尽可能简短明了(但不使用折叠表达式。这只是一个玩具问题,但在以后的应用程序中我想避免使用折叠表达式):
Additive auto sum(Additive auto&& val, Additive auto&&... vals) {
auto add = [](Additive auto&& val1, Additive auto&& val2) {
return val1 + val2;
}; // neccessary??
if constexpr(sizeof...(vals) == 1) {
return add(val, std::forward<decltype(vals)>(vals)...); // (1)
//return val + std::forward<decltype(vals)>(vals)...; // (2)
}
else return val + sum(std::forward<decltype(vals)>(vals)...);
}
使用第 (1) 行可以编译上述代码,但它需要 'add' lambda 的定义。但是,第 (2) 行没有编译,我在 gcc 中收到以下错误:parameter packs not expanded with ‘...’。如果我在第 (2) 行中的 std::forward 表达式周围添加括号,我会收到以下错误: expected binary operator before ‘)’ token.
有什么方法可以将长度为 1 的参数包传递给运算符吗?
template<class... Additive> decltype(auto) sum(Additive &&...val) {
return (std::forward<Additive>(val) + ...);
}
?
Offtopic:不确定Op的真正需求,我不小心快速设计了一件我一直在想的东西,不时。 :D
#include <iostream>
#include <functional>
#include <type_traits>
template<class... Fs> struct Overloads;
template<class F, class... Fs> struct Overloads<F, Fs...>: Overloads<Fs...> {
using Fallback = Overloads<Fs...>;
constexpr Overloads(F &&f, Fs &&...fs): Fallback(std::forward<Fs>(fs)...), f(std::forward<F>(f)) {}
template<class... Args> constexpr decltype(auto) operator()(Args &&...args) const {
if constexpr(std::is_invocable_v<F, Args...>) return std::invoke(f, std::forward<Args>(args)...);
else return Fallback::operator()(std::forward<Args>(args)...);
}
private:
F f;
};
template<class... Fs> Overloads(Fs &&...fs) -> Overloads<Fs...>;
template<class F> struct Overloads<F> {
constexpr Overloads(F &&f): f(std::forward<F>(f)) {}
template<class... Args> constexpr decltype(auto) operator()(Args &&...args) const {
return std::invoke(f, std::forward<Args>(args)...);
}
private:
F f;
};
template<> struct Overloads<> {
template<class... Args> constexpr void operator()(Args &&...) const noexcept {}
};
constexpr int f(int x, int y) noexcept { return x + y; }
void g(int x) { std::cout << x << '\n'; }
template<class... Vals> decltype(auto) omg(Vals &&...vals) {
static constexpr auto fg = Overloads(f, g);
return fg(std::forward<Vals>(vals)...);
}
int main() {
omg(omg(40, 2));
}
>_<
拥抱 negative thinking 的力量,从零而不是一开始归纳:
auto sum(auto &&val, auto &&...vals) {
if constexpr (sizeof...(vals) == 0)
return val;
else
return val + sum(std::forward<decltype(vals)>(vals)...);
}
以上定义的副作用是 sum(x)
现在可以编译 return x
。 (事实上 ,您甚至可以使函数使用 no 参数,方法是将其设置为 return 零,但问题出现了:哪种类型的零?为了避免必须去那里,我没有定义这个案例。)如果你坚持只从 arity 2 向上定义 sum
,你可以改用这个:
auto sum(auto &&val0, auto &&val1, auto &&...vals) {
if constexpr (sizeof...(vals) == 0)
return val0 + val1;
else
return val0 + sum(std::forward<decltype(val1)>(val1),
std::forward<decltype(vals)>(vals)...);
}
但是,只要有必要,您就应该允许使用“无意义”的情况:它使代码更简单、更通用。注意例如在后一个定义中加法运算符是如何出现两次的:这实际上是在复制两种情况之间的折叠逻辑(在这种情况下它只是一个加法,所以它相对简单,但是对于更复杂的操作它可能更麻烦) ,而处理退化的情况通常是微不足道的,不会重复任何东西。
(我省略了概念注释,因为它们似乎与主要问题没有特别相关。)
您可以将一项解包到一个变量中并使用它:
if constexpr (sizeof...(vals) == 1) {
auto&& only_value(std::forward<decltype(vals)>(vals)...);
return val + only_value;
}
我正在编写一个小的可变求和函数(使用 c++20,但我的问题将与 c++17 语法相同)。我想让下面的代码尽可能简短明了(但不使用折叠表达式。这只是一个玩具问题,但在以后的应用程序中我想避免使用折叠表达式):
Additive auto sum(Additive auto&& val, Additive auto&&... vals) {
auto add = [](Additive auto&& val1, Additive auto&& val2) {
return val1 + val2;
}; // neccessary??
if constexpr(sizeof...(vals) == 1) {
return add(val, std::forward<decltype(vals)>(vals)...); // (1)
//return val + std::forward<decltype(vals)>(vals)...; // (2)
}
else return val + sum(std::forward<decltype(vals)>(vals)...);
}
使用第 (1) 行可以编译上述代码,但它需要 'add' lambda 的定义。但是,第 (2) 行没有编译,我在 gcc 中收到以下错误:parameter packs not expanded with ‘...’。如果我在第 (2) 行中的 std::forward 表达式周围添加括号,我会收到以下错误: expected binary operator before ‘)’ token.
有什么方法可以将长度为 1 的参数包传递给运算符吗?
template<class... Additive> decltype(auto) sum(Additive &&...val) {
return (std::forward<Additive>(val) + ...);
}
?
Offtopic:不确定Op的真正需求,我不小心快速设计了一件我一直在想的东西,不时。 :D
#include <iostream>
#include <functional>
#include <type_traits>
template<class... Fs> struct Overloads;
template<class F, class... Fs> struct Overloads<F, Fs...>: Overloads<Fs...> {
using Fallback = Overloads<Fs...>;
constexpr Overloads(F &&f, Fs &&...fs): Fallback(std::forward<Fs>(fs)...), f(std::forward<F>(f)) {}
template<class... Args> constexpr decltype(auto) operator()(Args &&...args) const {
if constexpr(std::is_invocable_v<F, Args...>) return std::invoke(f, std::forward<Args>(args)...);
else return Fallback::operator()(std::forward<Args>(args)...);
}
private:
F f;
};
template<class... Fs> Overloads(Fs &&...fs) -> Overloads<Fs...>;
template<class F> struct Overloads<F> {
constexpr Overloads(F &&f): f(std::forward<F>(f)) {}
template<class... Args> constexpr decltype(auto) operator()(Args &&...args) const {
return std::invoke(f, std::forward<Args>(args)...);
}
private:
F f;
};
template<> struct Overloads<> {
template<class... Args> constexpr void operator()(Args &&...) const noexcept {}
};
constexpr int f(int x, int y) noexcept { return x + y; }
void g(int x) { std::cout << x << '\n'; }
template<class... Vals> decltype(auto) omg(Vals &&...vals) {
static constexpr auto fg = Overloads(f, g);
return fg(std::forward<Vals>(vals)...);
}
int main() {
omg(omg(40, 2));
}
>_<
拥抱 negative thinking 的力量,从零而不是一开始归纳:
auto sum(auto &&val, auto &&...vals) {
if constexpr (sizeof...(vals) == 0)
return val;
else
return val + sum(std::forward<decltype(vals)>(vals)...);
}
以上定义的副作用是 sum(x)
现在可以编译 return x
。 (事实上 ,您甚至可以使函数使用 no 参数,方法是将其设置为 return 零,但问题出现了:哪种类型的零?为了避免必须去那里,我没有定义这个案例。)如果你坚持只从 arity 2 向上定义 sum
,你可以改用这个:
auto sum(auto &&val0, auto &&val1, auto &&...vals) {
if constexpr (sizeof...(vals) == 0)
return val0 + val1;
else
return val0 + sum(std::forward<decltype(val1)>(val1),
std::forward<decltype(vals)>(vals)...);
}
但是,只要有必要,您就应该允许使用“无意义”的情况:它使代码更简单、更通用。注意例如在后一个定义中加法运算符是如何出现两次的:这实际上是在复制两种情况之间的折叠逻辑(在这种情况下它只是一个加法,所以它相对简单,但是对于更复杂的操作它可能更麻烦) ,而处理退化的情况通常是微不足道的,不会重复任何东西。
(我省略了概念注释,因为它们似乎与主要问题没有特别相关。)
您可以将一项解包到一个变量中并使用它:
if constexpr (sizeof...(vals) == 1) {
auto&& only_value(std::forward<decltype(vals)>(vals)...);
return val + only_value;
}