Home > Net >  Implicit conversion of initializer lists and perfect forwarding
Implicit conversion of initializer lists and perfect forwarding

Time:09-15

I'm trying to make perfect forwarding work with initializer lists. For the sake of the example, I'd like to have a variadic function that calls into another function, and still enjoy automatic conversion of initializer lists of the latter:

#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
}

The error is

example.cpp: In function ‘int main()’:
example.cpp:21:21: error: too many arguments to function ‘void 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 of ‘void f(Args&& ...) [with Args = {}]’:
example.cpp:21:21:   required from here
example.cpp:14:15: error: too few arguments to function ‘void 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)
      |      ^~~~~

Am I making any obvious mistake here?

CodePudding user response:

The compiler is not able to recognize the type you are sending in the third case.

If you use

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

everything works.

This post has some detailed explanation and quotes the relevant part of the standard. It is for a slightly different case but the explanation still applies.

CodePudding user response:

The problem is that the {1, 2, 3} argument to your second call to the templated f function is not sufficiently 'specific' for the compiler to unambiguously deduce its type in template substitution.

Explicitly defining that argument's type will resolve the issue:

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

A very similar case is given (as an example of an error) on this cppreference page.

  • Related