我不明白尝试传递可变数量的初始值设定项列表时的错误消息:
template<typename... Values>
void foo(Values...)
{
}
int main()
{
foo(1, 2, 3, "hello", 'a'); // OK
foo({1}, {2, 3}); // ERROR
}
错误消息抱怨参数过多:
prog.cpp: In function ‘int main()’:
prog.cpp:9:20: error: too many arguments to function
‘void foo(Values ...) [with Values = {}]’
foo({1}, {2, 3});
^
prog.cpp:2:6: note: declared here
void foo(Values...)
^
但是,我不应该不能传递尽可能多的参数吗?[同源链接]
问题可能是可推导性。 {}
可以是任何参数的统一初始值设定项。
这有效:
#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});
}
在科里鲁现场观看
问题不在于变量参数,而在于编译器无法推断大括号括起来的初始值设定项列表的类型,但声明参数的情况除外 std::initializer_list<T>
§ 14.8.2.1 通过比较每个函数来推导模板参数 模板参数类型(称为 P(与对应的类型 调用的参数(称为 A(,如下所述。如果删除 来自 P 的参考文献和 cv 限定符给出了 std::initializer_list 对于某些 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
问题确实是可演绎性,正如其他答案所提到的。您可以在调用函数时指定要 foo 的参数类型,而不是提供采用initializer_list的第二个函数:
#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});
}
然而,决定如何处理每个参数是另一个问题。
[编辑]:想法取自 std::shared_ptr 和初始值设定项列表
很糟糕。考虑一个简单的 print(( 实用程序:
template <typename ...Args>
void print ( Args&&... args) ;
所有这些都将起作用:
print("Word", 12, 13.0f, true );
元组也可以工作(忽略所需的实现(:
auto tup = std::make_tuple("A", true, 42f ) ;
print("nTuple I can pass it in ", tup );
但这些都不起作用
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(( 实用程序:
print("nMy list is:t", {1,2,3,4}) ; // error: function print() does not take 2 arguments?
这里缺少一些明显的东西吗?我想在对 print(( 的调用中混合任何内容,因为它的声明所暗示。
任何人?
[编辑2017-11-08]
有人建议
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)) ;
但是,可惜的是,MSVC 14.11.25503(截至撰写本文时的最新版本(无法编译此内容。错误来自
1>c:program files (x86)microsoft visual
studio2017communityvctoolsmsvc14.11.25503includeutility(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
studio2017communityvctoolsmsvc14.11.25503includeutility(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
studio2017communityvctoolsmsvc14.11.25503includetuple(1051):
note: see reference to variable template 'const ::size_t
tuple_size_v<std::initializer_list<int> >' being compiled
我相信没有人想要MSVC错误转储的其余部分...是我还是他们?
当然,将 print(( 作为通用 lambda 并不能解决任何问题。
/*
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
我知道 init 列表的 C++17 类型推导得到了加强和改进,但我看不到任何可以帮助我理解这是否可行的东西?
终于看来应该是了。