C++ 无法将多个初始值设定项列表传递给变量函数模板
我不理解尝试传递可变数量的初始值设定项列表时出现的错误消息:C++ 无法将多个初始值设定项列表传递给变量函数模板,c++,templates,c++11,variadic-templates,initializer-list,C++,Templates,C++11,Variadic Templates,Initializer List,我不理解尝试传递可变数量的初始值设定项列表时出现的错误消息: template<typename... Values> void foo(Values...) { } int main() { foo(1, 2, 3, "hello", 'a'); // OK foo({1}, {2, 3}); // ERROR } 然而,我是否应该不能传递我想要的那么多参数?[]这个问题可能是可推断的{}可以是任何参数的统一初始值设定项 这项工作:
template<typename... Values>
void foo(Values...)
{
}
int main()
{
foo(1, 2, 3, "hello", 'a'); // OK
foo({1}, {2, 3}); // ERROR
}
然而,我是否应该不能传递我想要的那么多参数?[]这个问题可能是可推断的
{}
可以是任何参数的统一初始值设定项
这项工作:
#include <initializer_list>
template<typename... Values>
void foo(std::initializer_list<Values>... args)
{
}
template<typename... Values>
void foo(Values&&... args)
{
}
int main()
{
foo(1, 2, 3, "hello", 'a');
foo({1}, {2, 3});
}
#包括
模板
void foo(标准::初始值设定项\u列表…参数)
{
}
模板
void foo(值和参数)
{
}
int main()
{
foo(1,2,3,“你好”,“a”);
foo({1},{2,3});
}
请参见问题不在于varadic参数,而是编译器无法推断括号内初始值设定项列表的类型,除非您声明了
std::initializer\u list
§14.8.2.1通过比较每个函数来进行模板参数推导
模板参数类型(称为P)与对应的
调用的参数(称为A),如下所述。如果删除
来自P的引用和cv限定符给出了std::initializer\u列表
对于某些P0,参数是初始值设定项列表(8.5.4),则
对初始值设定项的每个元素执行演绎
列表,以P0为函数模板参数类型和
初始值设定项元素作为其参数否则,为初始值设定项列表
参数导致参数被视为非推断上下文
(14.8.2.5).
下面甚至有一个例子
template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
模板无效g(T);
g({1,2,3});//错误:没有为T推导参数
正如其他答案所提到的,问题确实是可推断性。您可以在调用函数时指定foo的参数类型,而不是提供第二个采用初始值设定项\u列表的函数:
#include <initializer_list>
template<typename... Values>
void foo(Values...)
{
}
int main()
{
foo(1, 2, 3, "hello", 'a');
foo(std::initializer_list<int>{1}, std::initializer_list<int>{2, 3});
}
#包括
模板
无效foo(值…)
{
}
int main()
{
foo(1,2,3,“你好”,“a”);
foo(std::initializer\u list{1},std::initializer\u list{2,3});
}
然而,决定如何处理每个参数是另一个问题
[编辑]:这个想法来自于这很糟糕。考虑一个简单的打印()实用程序: Tuple也可以工作(忽略所需的实现): 但这些都不管用
print({1,2,3}); // spurious error messages
print({1}, {2}, {3}); // also
print("\nThe tuple: ", {12, 34, 56 } ) ; //also
上述“解决方案”也无济于事:
template<typename ...Args>
inline void print(const std::initializer_list<Args>&... il_);
这里有什么明显的缺失吗?我想混合调用print()中的任何内容,因为它的声明暗示了这一点
有人吗
[编辑2017-11-08]
有人建议
print("\nMy list is:\t", std::initializer_list<int>{1,2,3,4}) ;
但遗憾的是,MSVC 14.11.25503(截至本文撰写之时的最新版本)无法编译此文件。错误来自于
1>c:\program files (x86)\microsoft visual
studio\2017\community\vc\tools\msvc\14.11.25503\include\utility(415):
error C2027: use of undefined type 'std::tuple_size<_Ty>'
1> with
1> [
1> _Ty=std::initializer_list<int>
1> ]
1>c:\program files (x86)\microsoft visual
studio\2017\community\vc\tools\msvc\14.11.25503\include\utility(415):
note: see declaration of 'std::tuple_size<_Ty>'
1> with
1> [
1> _Ty=std::initializer_list<int>
1> ]
1>c:\program files (x86)\microsoft visual
studio\2017\community\vc\tools\msvc\14.11.25503\include\tuple(1051):
note: see reference to variable template 'const ::size_t
tuple_size_v<std::initializer_list<int> >' being compiled
我知道C++17初始化列表的类型推导得到了加强和改进,但我看不到有任何东西可以帮助我理解这是可行的吗
最后看来应该是这样。的确如此<代码>模板无效foo(T)代码>无法从参数
foo({1,2})推断
(参数T
成为非推断上下文),但有一些特殊规则允许推断模板void foo(std::initializer\u list)
(和同一个参数)。您能否展开“{}
可以是任何参数的统一初始值设定项。”部分?我不确定我是否理解你的意思。我的意思是编译器不会“假定”它必须是一个初始值设定项列表(注意,初始值设定项列表中的元素类型不必是同构的)。相反,它可以是任何旧UDT/内置的统一初始化。反之亦然:如果函数重载接受初始值设定项列表,则该重载总是首选接受{}
样式参数。此参考资料展示了一个非常准确的问题示例@Falmari CPPFREFERENCE以高质量的金块让我惊讶。这不仅仅是一个标准的图书馆参考资料。+1是我的“变通方法”的一个完美的配套引用。确实值得升级为一个答案。谢谢你的钻研
print({1,2,3}); // spurious error messages
print({1}, {2}, {3}); // also
print("\nThe tuple: ", {12, 34, 56 } ) ; //also
template<typename ...Args>
inline void print(const std::initializer_list<Args>&... il_);
print("\nMy list is:\t", {1,2,3,4}) ; // error: function print() does not take 2 arguments?
print("\nMy list is:\t", std::initializer_list<int>{1,2,3,4}) ;
#define DBJ_IL(T,...) (std::initializer_list<T>{__VA_ARGS__})
print("\nMy list is:\t", DBJ_IL(int,1,2,3,4)) ;
1>c:\program files (x86)\microsoft visual
studio\2017\community\vc\tools\msvc\14.11.25503\include\utility(415):
error C2027: use of undefined type 'std::tuple_size<_Ty>'
1> with
1> [
1> _Ty=std::initializer_list<int>
1> ]
1>c:\program files (x86)\microsoft visual
studio\2017\community\vc\tools\msvc\14.11.25503\include\utility(415):
note: see declaration of 'std::tuple_size<_Ty>'
1> with
1> [
1> _Ty=std::initializer_list<int>
1> ]
1>c:\program files (x86)\microsoft visual
studio\2017\community\vc\tools\msvc\14.11.25503\include\tuple(1051):
note: see reference to variable template 'const ::size_t
tuple_size_v<std::initializer_list<int> >' being compiled
/*
forget templates
*/
namespace dbj { namespace {
auto print = [](auto... param)
{
if constexpr (sizeof...(param) > 0) {
char dummy[sizeof...(param)] = {
(( std::cout << param), 0)...
};
}
};
} }
dbj::print({1,2,3}) ; // msvc compilation error