如何在可变参数函数中传递std::initializer_list?
解决可变参数函数处理std::initializer_list的问题
原实现失败原因
第一种实现问题
传递{10, 20, 30, 40}时,这是花括号初始化列表(braced-init-list),模板参数推导规则不会自动将其转换为std::initializer_list<T>。可变参数函数的模板参数推导无法识别这个列表对应的类型,导致无法匹配到处理std::initializer_list的func_重载。
第二种实现问题
模板template <typename T, typename S> void func(T t)中的S属于无法推导的模板参数。即便T是std::initializer_list<S>,编译器也无法从T反向推导出S,因此该模板不会被实例化,initializer_list的处理逻辑永远不会执行。
解决方案
方案1:调用时显式构造std::initializer_list
直接在调用时将花括号列表包装为std::initializer_list,让编译器能明确匹配到对应重载:
#include <iostream> #include <initializer_list> template <typename T> void func_(std::initializer_list<T> list ) { std::cout << "{ "; for( const T& elem : list ) { std::cout << elem << ", "; } std::cout << "}" << std::endl; } template <typename T> void func_(T t) { std::cout << t << std::endl; } void func(){} template<typename T, typename... Args> void func(T t, Args... args) { func_(t); func(args...) ; } int main() { // 显式构造std::initializer_list<int> func( 1, 2.5, 'a', "Hello", std::initializer_list<int>{10, 20, 30, 40} ); }
方案2:C++17+折叠表达式版本(自动推导)
给func增加专门处理std::initializer_list的重载,同时用折叠表达式简化可变参数处理(无需递归):
#include <iostream> #include <initializer_list> #include <type_traits> // 处理普通类型 template <typename T> std::enable_if_t<!std::is_same_v<T, std::initializer_list<typename T::value_type>>, void> print_single(T t) { std::cout << t << std::endl; } // 处理std::initializer_list template <typename T> void print_single(std::initializer_list<T> list) { std::cout << "{ "; for (const auto& elem : list) { std::cout << elem << ", "; } std::cout << "}" << std::endl; } // 可变参数函数,用折叠表达式遍历所有参数 template <typename... Args> void func(Args&&... args) { (print_single(std::forward<Args>(args)), ...); } int main() { // 直接传递花括号列表,编译器自动推导为std::initializer_list<int> func(1, 2.5, 'a', "Hello", {10, 20, 30, 40}); }
方案3:C++11兼容递归版本
如果需要兼容C++11,可以给func增加std::initializer_list的重载,确保递归时能正确匹配:
#include <iostream> #include <initializer_list> template <typename T> void func(std::initializer_list<T> list) { std::cout << "{ "; for (const T& elem : list) { std::cout << elem << ", "; } std::cout << "}" << std::endl; } template <typename T> void func(T t) { std::cout << t << std::endl; } template <typename T, typename... Args> void func(T t, Args... args) { func(t); func(args...); } int main() { // C++11需显式构造,C++14+可直接传{10,20,30,40} func(1, 2.5, 'a', "Hello", std::initializer_list<int>{10, 20, 30, 40}); }
以上方案均可实现你期望的输出效果。
内容的提问来源于stack exchange,提问作者Bruno Xavier
相关产品推荐
相关产品推荐

