可变参数模板是采用可变数量参数的模板。
我不明白为什么这不起作用。了解模板和可变表达式折叠的人能否解释正在发生的事情并给出可行的解决方案? #包括 我不明白为什么这不起作用。了解模板和可变表达式折叠的人可以解释正在发生的事情并给出可行的解决方案吗? #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; 一条单独的指令来处理具有一个参数的情况。
这是我连接元组的二元运算符: 模板 constexpr decltype(auto) 运算符+(const std::tuple &tup1, ...
C++26 在使模板参数包更加符合人体工程学方面取得了一些进展。例如 P2662:包索引已被纳入标准。 有了这个和其他相关的提案,什么是......
我想构造一个类型,它是具有不同模板参数类型的同一类的元组。我是说: 想象一下我们有一堂课 模板 A级 { //.... 细节 } 我...
我正在尝试构建一个模板类,一旦使用其可变参数构造,其成员函数就可以使用这些参数,而无需用户手动将它们插入回去。这段代码(
背景与目标 我想创建某种数据实用程序,它存储 std::stringstream 以及内容当前的格式。这将为您提供类型安全和智能...
对于作业问题,我们必须使用可变参数模板和表达式模板。为了看看,他们做了一个练习来展示他们所谓的“简单”和“&”之间的区别......
我想传递一个重载函数作为可变参数模板函数的参数。我了解如何使用一个特定函数(使用 static_cast)来做到这一点。不过,我想知道是否...
我需要一种有效的方法将 0 到 N-1 范围内的运行时动态 int 转换为模板参数。 也就是说,从逻辑上讲,我想创建一个在 0 和 ... 之间切换数字的开关
给出以下代码: void foo(int x, int y, int z, int u) { } 模板 A 类; 模板<>类A<>{}; 模板 类...
错误C3856:“RecursiveType”:符号不是类模板[重复]
我正在尝试使用像 std::tuple 这样的递归模板创建类型,不幸的是它无法编译,但是我的做法似乎与元组源代码中的方式相同。我正在使用 Visual Studio 进行编译...
我正在尝试使用像 std::tuple 这样的递归模板创建类型,不幸的是它无法编译,但是我的做法似乎与元组源代码中的方式相同。我正在使用 Visual Studio 进行编译...
我在尝试传递已经初始化的字符串时遇到问题,该字符串实际上没有正确接受重载: #包括 #包括 #包括 我在尝试传递已经初始化的字符串时遇到问题,该字符串实际上没有正确接受重载: #include <cstddef> #include <ranges> #include <algorithm> #include <iostream> template <std::size_t N> class A { char m_m[N]; public: A(char const (&p)[N]) { // Copy p to m_m std::ranges::copy(p, m_m); } }; template <std::size_t N> class B { public: B(A<N> a) { // Perform some operation on 'a' } }; int main() { auto k = B("test"); } 采取,过载正确,但我目前得到: prog.cc:26:22: error: no matching function for call to 'B(const char [5])' prog.cc:20:5: note: candidate: 'template<long unsigned int N> B(A<N>)-> B<N>' 20 | B(A<N> a) { 代码中的问题是类 B 的构造函数需要一个 A<N> 类型的对象,但您试图传递一个字符串文字,它是一个字符数组,而不是 A<N> 类型的对象。 您可以修改 B 构造函数以直接接受字符串文字。 这是代码的更新版本: #include <cstddef> #include <ranges> #include <algorithm> #include <iostream> template <std::size_t N> class A { char m_m[N]; public: A(char const (&p)[N]) { // Copy p to m_m std::copy(p, p + N, m_m); } }; template <std::size_t N> class B { public: B(const char (&p)[N]) { A<N> a(p); // Perform some operation on 'a' } }; int main() { auto k = B("test"); return 0; }
在可变非类型模板中,模板列表中的每个值都有其唯一类型: 模板 void print_type(const T &) { std::cout << typeid(T).name() << '\n'; }
以下代码来自《Modern C++ Tutorial: C++11/14/17/20 On the Fly》一书: 模板自动 printf3(T 值, Ts... args) { std::cout &...
以下代码来自《Modern C++ Tutorial: C++11/14/17/20 On the Fly》一书: 模板自动 printf3(T 值, Ts... args) { std::cout &...
我想知道是否可以过滤传递给可变参数模板(基于谓词模板)的类型,以生成另一个可变参数模板,其中包含满足预条件的类型...
我正在尝试为我的引擎构建一个事件系统。我的想法是存储指向我希望事件在事件结构中执行的函数的指针,但到目前为止我还没有成功。 我是
如何反转元组中的类型?例如,我希望reverse_tuple>::type 为std::tuple。我尝试执行以下操作,但它...
我有一个函数,它需要 3 个模板参数:两种类型和一个整数常量(用于特征存储要求)。它看起来像下面的模板: 模板 我有一个函数,它需要 3 个模板参数:两种类型和一个整数常量(用于特征存储要求)。它看起来像下面的模板: template <typename In, typename Out, Eigen::StorageOptions Options> void my_big_function(/* 3 Eigen parameters depending on template args... */) { /* Eigen::StorageOptions can also be an integer constant. */ /* Do stuff with matrices... */ } 由于这个函数需要使用多个模板“三元组”绑定到python,我认为这可能是模板参数包的一个很好的使用。 我想实现以下目标: // binds to python : // - my_big_function<float, int, ColMajor>(...) bind_my_big_function<float, int, Eigen::ColMajor>(m); // (1) // binds to python : // - my_big_function<float, int, ColMajor>(...) // - my_big_function<float, int, RowMajor>(...) // - my_big_function<double, int, RowMajor>(...) bind_my_big_function<float, int, Eigen::ColMajor, float, int, Eigen::RowMajor, double, int, Eigen::RowMajor>(m); // (2) 其中bind_my_big_function足够简单: template <typename MatIn, typename MatOut, Eigen::StorageOptions MatOptions, typename...RemainingArgs> void bind_my_big_function(pybind11::module_& m) { /* bind function taking MatIn, MatOut, MatOptions and go onto binding other variants of my_big_function */ } 虽然我肯定可以生成一些处理情况 (1) 的代码,但我无法弄清楚如何编写处理情况 (2) 的代码。我得到的最接近的是这样的: template < typename MatIn, typename MatOut, Eigen::StorageOptions MatOptions > void bind_my_big_function(pybind11::module_& m) { m.def("my_big_function_in_python", &my_big_function<MatIn, MatOut, MatOptions>, /* python arguments...*/); } template < typename MatIn, typename MatOut, Eigen::StorageOptions MatOptions, typename...RemainingArgs, typename = typename std::enable_if_t<sizeof...(RemainingArgs) != 0> > void bind_my_big_function(pybind11::module_& m) { m.def("my_big_function_in_python", &my_big_function<MatIn, MatOut, MatOptions>, /* python arguments...*/); bind_my_big_function<RemainingArgs...>(m); } 参数包应该这样使用吗?我能找到的唯一使用它们的例子是: 使用模板化函数参数, 一次使用单个包扩展“使用”(被调用的函数仅需要一种类型和一个可变参数模板包) 不确定我是否理解这个问题,但是如果你想实例化一些给定的foo<Ts...,Ts...,Ts...>,你可以包装函数模板,只需实例化它:Ts...