variadic-templates 相关问题

可变参数模板是采用可变数量参数的模板。

C++:使用折叠表达式实现“多米诺骨牌更新”

考虑以下代码: #包括 #包括 模板 无效 dominoe_update(P, Val&) {} 模板 考虑以下代码: #include <iostream> #include <functional> template<class Val, class P> void dominoe_update(P, Val&) {} template<class Val, class Lval, class... More, class P> void dominoe_update(P p, Val&& val, Lval& lval, More&... more) { if (p(val, lval)) { lval = val; // No need to forward since it'd potentialy chain more copies anyway dominoe_update(p, val, more...); } } int main(int, char**) { int i = 8, j = 9, k = 1; dominoe_update(std::less{}, 2, i, j, k); std::cout << i << ' ' << j << ' ' << k << '\n'; // Prints 2 2 1 return 0; } dominoe_update 使用 val 更新所有参数,直到 p 返回 false。 是否可以使用折叠表达式来实现上述函数以删除递归并删除基本情况函数?我认为这是不可能的,因为短路逻辑。 这是一种方法: template <class P, class Val, class... Lvals> void dominoe_update(P p, Val&& val, Lvals&&... lval) { ((/*if*/ p(val, lval) /*then*/ && (lval = val, true)) /*and next*/ && ...); } 演示 接受挑战。 template<typename P, typename Val, typename... Lval> void dominoe_update(P p, Val&& val, Lval&... lval) { bool go = true; ( (go && (go = p(val, lval)) ? (void(lval = val), 0) : 0), ...); } 演示

回答 2 投票 0

C++:使用折叠表达式进行编译时“多米诺骨牌更新”

考虑以下代码: #包括 #包括 模板 无效 dominoe_update(P, Val&) {} 模板 考虑以下代码: #include <iostream> #include <functional> template<class Val, class P> void dominoe_update(P, Val&) {} template<class Val, class Lval, class... More, class P> void dominoe_update(P p, Val&& val, Lval& lval, More&... more) { if (p(val, lval)) { lval = val; // No need to forward since it'd potentialy chain more copies anyway dominoe_update(p, val, more...); } } int main(int, char**) { int i = 8, j = 9, k = 1; dominoe_update(std::less{}, 2, i, j, k); std::cout << i << ' ' << j << ' ' << k << '\n'; // Prints 2 2 1 return 0; } dominoe_update 使用 val 更新所有参数,直到 p 返回 false。 主要问题:是否可以使用折叠表达式来实现上述函数以删除递归并删除基本情况函数?我认为这是不可能的,因为短路逻辑。 第二个问题:是否可以将谓词写为最后一个参数,而不是第一个?我知道在可变参数之后写参数是“复杂的”,但我认为在某些情况下推导规则允许这样做。 第三个问题:你认为这个函数有更好的名字吗?我正在考虑为常见情况提供一些实用函数,例如最小化和最大化,但是 dominoe_minimize 和 dominoe_maximize 作为通用名称对我来说听起来不太好。 接受挑战。 template<typename P, typename Val, typename... Lval> void dominoe_update(P p, Val&& val, Lval&... lval) { bool go = true; ( (go && (go = p(val, lval)) ? (void(lval = val), 0) : 0), ...); } 演示

回答 1 投票 0

在 C++ 模块中将可变数量的参数转发到 SpdLog

我是一名专业的 C# 开发人员,正在启动一个 C++ 副项目。我的第一步是使用 spdlog 进行记录和运行。由于这是一个新的现代项目,我正在使用模块。 ...

回答 1 投票 0

可变参数类的多重继承

我可以执行以下操作吗? 模板 A类{}; 模板 B 类:公共 A... {}; 我期待这种行为: 模板 B 类:...

回答 1 投票 0

带有可变参数模板的 C++ 概念

多年后我又回到了 C++,并试图掌握其中的概念。我编写了一个简单的测试代码,但出现了一个错误,我不太明白为什么会出现在这里。 模板 多年后我又回到了 C++,并试图掌握其中的概念。我编写了一个简单的测试代码,但出现了一个错误,我不太明白为什么会出现在这里。 template <typename T, typename U> concept addable = requires (T a, U b) { a + b; }; template <typename T> T test_add(T&& value) { return value; } template <typename T, typename... Args> auto test_add(T&& value, Args&&... rest) requires addable<T, decltype(test_add(forward<Args>(rest)...))> { return value + test_add(forward<Args>(rest)...); } 目标是检查返回表达式上是否有有效的+操作,但是当我像这样调用函数时: auto result = test_add(1, 3, 5); 我收到以下错误:“没有重载函数“test_add”的实例与参数列表匹配”。 这里出了什么问题? 看起来您希望 concept 是可变参数,因此您需要一个参数包,然后进行包扩展: template <class... Ts> concept addable = requires(Ts&&... ts) { (... + ts); }; 您的 test_add 函数模板可以替换为 one,它使用 concept 并在 + 运算符上使用折叠表达式: auto test_add(addable auto&&... values) { return (... + std::forward<decltype(values)>(values)); }

回答 1 投票 0

选择可变参数模板最后一个参数的有效方法

我知道如何选择可变参数模板的第一个参数: template< class...Args> struct select_first; template< class A, class ...Args> struct select_first{ 使用 t...

回答 8 投票 0

如果在可变参数模板类的成员函数声明中我将类类型指定为默认模板模板参数,它是有效的 C++ 吗? [重复]

简而言之:此代码可以在 clang++ (10.0) 中编译,但不能在 g++ (12.2) 中编译。哪一个是正确的? 模板 结构体V{ 模板 类 U=V,输入 n...

回答 1 投票 0

ranges::view 管道运算符 - 通过将 std::variant 参数隐藏到变量->选项模式来实现 std::visit 的单子链?

我的灵感来自 std::ranges 和 std::view 及其 |有助于链接不同算法的运算符,所以我希望将 std::get_if 和 std::visit 模式打包在引擎盖下以执行 inpl...

回答 1 投票 0

C++1y/C++14:将静态 constexpr 数组转换为非类型模板参数包?

假设我有一个静态存储持续时间的 constexpr 数组(已知范围): constexpr T input[] = /* ... */; 我有一个需要包的输出类模板: 模板 结构

回答 2 投票 0

如何通过元编程生成参数包?

假设 模板 void bar(); 我正在尝试编写一个模板结构 GimmePack 以便 栏< GimmePack::类型 >(); 是相同的 酒吧<

回答 3 投票 0

C++ 在给定基本元组类型和可变参数索引序列的情况下定义子元组类型

假设我有一个元组,例如使用 BaseTuple = std::tuple;,我想从给定的可变参数索引序列定义新类型,以及与 BaseTuple 相互转换的方法...

回答 1 投票 0

使用运算符>>折叠表达式[重复]

考虑以下代码片段: #包括 模板 void writeall(const types & ... items) { (std::cout << ... << items); } templat...

回答 1 投票 0

C++17 可变参数模板折叠

我不明白为什么这不起作用。了解模板和可变表达式折叠的人能否解释正在发生的事情并给出可行的解决方案? #包括 我不明白为什么这不起作用。了解模板和可变表达式折叠的人可以解释正在发生的事情并给出可行的解决方案吗? #include <iostream> #include <string> template <typename... Args> void print(Args... args) { std::string sep = " "; std::string end = "\n"; (std::cout << ... << sep << args) << end; } int main() { print(1, 2, 3); } 它应该打印出每个参数,参数之间有一个空格,末尾有一个换行符。如果您删除 sep <<,但打印时每个参数之间没有空格,它会起作用。 二进制折叠表达式的语法必须是以下之一: (pack op ... op init) (init op ... op pack) 你拥有的是(std::cout << ... << sep << args),它不适合任何一种形式。您需要像 (cout << ... << pack) 这样的东西,这就是删除 sep 有效的原因。 相反,您可以折叠逗号: ((std::cout << sep << args), ...); 或使用递归: template <class A, class... Args> void print(A arg, Args... args) { std::cout << arg; if constexpr (sizeof...(Args) > 0) { std::cout << sep; print(args...); } } 这可以工作,但它会打印一个尾随空格: template <typename... Args> void print(Args... args) { std::string sep = " "; std::string end = "\n"; ((std::cout << args << sep), ...) << end; } 现场魔杖盒示例 在这种情况下,正在执行逗号运算符的折叠,从而导致如下扩展: // (pseudocode) (std::cout << args<0> << sep), (std::cout << args<1> << sep), (std::cout << args<2> << sep), ..., (std::cout << args<N> << sep), 你真正想做的是: std::string sep = " "; std::string end = "\n"; (std::cout << ... << (sep << args)) << end; 因为您希望 (sep << args) 与 std::cout 一起向左折叠。这不起作用,因为 sep << args 不知道它正在流式传输到 std::cout 或根本不知道它正在流式传输; << 仅当左侧是流时才进行流式传输。 简而言之,问题在于sep << args不明白它正在流式传输。 你的另一个问题是 lambda 不够。 我们可以解决这个问题。 template<class F> struct ostreamer_t { F f; friend std::ostream& operator<<(std::ostream& os, ostreamer_t&& self ) { self.f(os); return os; } template<class T> friend auto operator<<(ostreamer_t self, T&& t) { auto f = [g = std::move(self.f), &t](auto&& os)mutable { std::move(g)(os); os << t; }; return ostreamer_t<decltype(f)>{std::move(f)}; } }; struct do_nothing_t { template<class...Args> void operator()(Args&&...)const {} }; const ostreamer_t<do_nothing_t> ostreamer{{}}; template <typename... Args> void print(Args... args) { std::string sep = " "; std::string end = "\n"; (std::cout << ... << (ostreamer << sep << args)) << end; } 活生生的例子。 (我还使用了 sep 的文字来确保我使用右值)。 ostreamer 捕获对它是 << 的事物的引用,然后将它们转储到 << 到 ostream。 整个过程对编译器来说应该是透明的,因此一个好的优化器应该消除涉及的所有内容。 正如其他人所回答的,您正在尝试使用错误的 fold-expression 格式。 您可以通过非常简单的方式使用 lambda 助手来达到您的目的: template <typename... Args> void print(Args&&... args) { std::string sep = " "; std::string end = "\n"; auto streamSep = [&sep](const auto& arg) -> decltype(arg) { std::cout << sep; return arg; }; (std::cout << ... << streamSep(args)) << end; } 这将遵循您编写的代码中预期的行为。但是,如果您想避免第一个参数之前的 sep,您可以使用以下内容: template <typename Arg, typename... Args> void print(Arg&& arg, Args&&... args) { std::string sep = " "; std::string end = "\n"; auto streamSep = [&sep](const auto& arg) -> decltype(arg) { std::cout << sep; return arg; }; std::cout << arg; (std::cout << ... << streamSep(args)) << end; } 另一种方法是下一个: #include <iostream> template<class U, class... T> void printSpaced(const U& u, const T&... args) { using std::cout; using std::endl; ((cout << u) << ... << (cout << ' ', args)) << endl; } 这样你就不会得到前导/尾随空格 用途: printSpaced(1, 2, "Hello", 4.5f); //Output 1 2 Hello 4.5 and no trailing space 你可以尝试这样的事情 template <typename... Args> void print(Args... args) { bool first = true; auto lambda = [&](auto param) { if( !first) std::cout << ','; first= false; return param; }; ((std::cout << lambda(args)), ...); } lambda 确保分隔符仅插入在两个项目之间。 另一方面,如果你不想使用 lambda,你可以重载模板: template<typename T> void print(T item) { std::cout << item; } template<typename T, typename... Args> void print(T item, Args... args) { print(item); std::cout << ','; print(args...); } 如果您不想要前导/尾随sep: template <typename First, typename... Rest> void print(First first, Rest... rest) { std::string sep = " "; std::string end = "\n"; std::cout << first; ((std::cout << sep << rest), ...); std::cout << end; } 您需要制作 std::cout << end; 一条单独的指令来处理具有一个参数的情况。

回答 7 投票 0

Clang 在折叠表达式中找不到模板二元运算符

这是我连接元组的二元运算符: 模板 constexpr decltype(auto) 运算符+(const std::tuple &tup1, ...

回答 3 投票 0

C++26 中最简单的元组实现是什么?

C++26 在使模板参数包更加符合人体工程学方面取得了一些进展。例如 P2662:包索引已被纳入标准。 有了这个和其他相关的提案,什么是......

回答 1 投票 0

从模板参数类型构造类类型的元组

我想构造一个类型,它是具有不同模板参数类型的同一类的元组。我是说: 想象一下我们有一堂课 模板 A级 { //.... 细节 } 我...

回答 2 投票 0

构造对象后将可变参数传递给方法

我正在尝试构建一个模板类,一旦使用其可变参数构造,其成员函数就可以使用这些参数,而无需用户手动将它们插入回去。这段代码(

回答 1 投票 0

C++ 递归模板专业化 - 缺少正确的参数包扩展

背景与目标 我想创建某种数据实用程序,它存储 std::stringstream 以及内容当前的格式。这将为您提供类型安全和智能...

回答 1 投票 0

递归添加多个向量元素的函数以某种方式获得双精度作为参数

对于作业问题,我们必须使用可变参数模板和表达式模板。为了看看,他们做了一个练习来展示他们所谓的“简单”和“&”之间的区别......

回答 1 投票 0

在可变参数模板中使用函数的多个重载

我想传递一个重载函数作为可变参数模板函数的参数。我了解如何使用一个特定函数(使用 static_cast)来做到这一点。不过,我想知道是否...

回答 1 投票 0

© www.soinside.com 2019 - 2024. All rights reserved.