将多个初始值设定项列表传递到可变参数函数模板时遇到问题



我不明白尝试传递可变数量的初始值设定项列表时的错误消息:

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 类型推导得到了加强和改进,但我看不到任何可以帮助我理解这是否可行的东西?

终于看来应该是了。

相关内容

  • 没有找到相关文章

最新更新