初始化列表的隐式转换和完美转发

6

我想让完美转发和初始化列表一起使用。举个例子,我想创建一个可变参数函数,可以调用另一个函数,同时仍然支持后者的自动转换初始化列表:

#include <iostream>  
#include <vector>

void hello(std::string const& text, std::vector<int> const& test)
{
  std::cout << "hello " << text << " " << test.size() << std::endl;      
}

template<class ... Args>
void f(Args&& ... args)
{
  return hello(std::forward<Args>(args)...);
}

int main()
{
  hello("world", {1,2,3});  // WORKS
  f("world", std::vector<int>({1,2,3})); // WORKS
  f("world", {1,2,3});  // COMPILER ERROR
}

错误是

example.cpp: In function ‘int main()’:
example.cpp:21:21: error: too many arguments to functionvoid f(Args&& ...) [with Args = {}]’
   21 |   f("world", {1,2,3});
      |                     ^
example.cpp:12:6: note: declared here
   12 | void f(Args&& ... args)
      |      ^
example.cpp: In instantiation ofvoid f(Args&& ...) [with Args = {}]’:
example.cpp:21:21:   required from here
example.cpp:14:15: error: too few arguments to functionvoid hello(const string&, const std::vector<int>&)’
   14 |   return hello(std::forward<Args>(args)...);
      |          ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
example.cpp:6:6: note: declared here
    6 | void hello(std::string const& text, std::vector<int> const& test)
      |      ^~~~~

我这里有没有犯什么明显的错误?

2个回答

5

在第三种情况下,编译器无法识别您发送的类型。

如果您使用

f("world", std::initializer_list<int>{1,2,3});

一切正常。

这篇文章详细解释了相关标准的引用。虽然它是针对略有不同的情况,但解释仍适用。


3

问题在于传递给第二次调用模板化的f函数的参数{1, 2, 3}不足够“具体”,以至于编译器无法在模板替换中明确推断其类型。

明确定义该参数的类型将解决此问题:

f("world", std::initializer_list<int>{ 1, 2, 3 });

在这个cppreference页面中,提供了一个非常相似的案例(作为错误的示例)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接