尝试传递可变数量的初始化列表时,我不明白错误消息:
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...)
^
但是,我是否应该无法传递尽可能多的参数? [ideone link]
答案 0 :(得分:11)
问题可能是可导性。 {}
可以是任何参数的统一初始化器。
这有效:
#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});
}
答案 1 :(得分:7)
问题不在于varadic参数,而是编译器无法推断括号括起初始化列表的类型,除非您声明参数std::initializer_list<T>
§14.8.2.1通过比较每个函数来完成模板参数推导 模板参数类型(称之为P)与对应的类型 呼叫的参数(称之为A)如下所述。如果删除 来自P的引用和cv限定符给出了std :: initializer_list 对于某些P0,参数是初始化列表(8.5.4),然后 相反,对于初始化器的每个元素执行推导 列表,将P0作为函数模板参数类型和 initializer元素作为其参数。 否则,是初始化列表 参数使参数被视为非推导上下文 (14.8.2.5)。
下面还有一个例子
template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
答案 2 :(得分:2)
正如其他答案所提到的那样,问题确实是可导性的。您可以在调用函数时指定foo的参数类型,而不是提供第二个带初始化列表的函数:
#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});
}
然而,决定如何处理每个参数是另一个问题。
答案 3 :(得分:2)
这很糟糕。考虑一个简单的print()实用程序:
template <typename ...Args>
void print ( Args&&... args) ;
所有这一切都有效:
print("Word", 12, 13.0f, true );
Tuple也有效(忽略所需的实现):
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
以上&#34;解决方案&#34;也没有帮助:
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}) ;
为了解决这方面的痛苦,我很勉强承认我已经定义了这个宏&#34;帮助&#34;
#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
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
我确信没有人想要其余的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)...
};
}
};
} }
即使一个传递单个简单的init列表,也不会使用与上面相同的错误进行编译...
dbj::print({1,2,3}) ; // msvc compilation error
我知道C ++ 17类型的init列表的演绎得到了加强和改进,但我看不出有什么可以帮助我理解这是否可行?
最后它似乎应该是。