无法将多个初始化程序列表传递给可变参数函数模板

时间:2013-11-18 22:14:07

标签: 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
}

错误消息抱怨参数太多:

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]

4 个答案:

答案 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});
}

查看 Live on Coliru

答案 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});
}

然而,决定如何处理每个参数是另一个问题。

[编辑]:想法取自std::shared_ptr and initializer lists

答案 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列表的演绎得到了加强和改进,但我看不出有什么可以帮助我理解这是否可行?

最后它似乎应该是。