Having trouble passing multiple initializer lists to variadic function template

后端 未结 4 2147
自闭症患者
自闭症患者 2020-12-20 14:16

I don\'t understand the error message when trying to pass a variable number of initializer lists:

template
void foo(Values...)
{
}
         


        
相关标签:
4条回答
  • 2020-12-20 15:00

    The problem is indeed deducibility, as mentioned by other answers. Instead of providing a second function taking an initializer_list, you may specify the type of the argument to foo when calling the function:

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

    Deciding how to treat each parameter, is another question, however.

    [EDIT]: Idea is taken from std::shared_ptr and initializer lists

    0 讨论(0)
  • 2020-12-20 15:05

    The problem is likely deducibility. {} could be uniform initializers to any of the arguments.

    This works:

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

    See it Live on Coliru

    0 讨论(0)
  • 2020-12-20 15:10

    The issue is not with the varadic arguments, but that the compiler cannot deduce the type of a brace enclosed initializer list, except for the case where you've declare the parameter of std::initializer_list<T>

    § 14.8.2.1 Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below. If removing references and cv-qualifiers from P gives std::initializer_list for some P0 and the argument is an initializer list (8.5.4), then deduction is performed instead for each element of the initializer list, taking P0 as a function template parameter type and the initializer element as its argument. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context (14.8.2.5).

    There's even an example right below

    template<class T> void g(T);
    g({1,2,3}); // error: no argument deduced for T
    
    0 讨论(0)
  • 2020-12-20 15:12

    This is bad. Consider a simple print() utility:

      template <typename ...Args>
      void print ( Args&&... args) ;
    

    All of this would work:

    print("Word", 12, 13.0f, true );
    

    Tuple also works (ignore the implementation required):

    auto tup = std::make_tuple("A", true, 42f ) ;    
    print("\nTuple I can pass it in ", tup );
    

    But none of this works

    print({1,2,3}); // spurious error messages
    print({1}, {2}, {3}); // also 
    print("\nThe tuple: ", {12, 34, 56 } ) ; //also
    

    The above "solution" does not help too:

    template<typename ...Args>
    inline  void print(const std::initializer_list<Args>&... il_);
    

    This (as above) does not give usable print() utility :

    print("\nMy list is:\t", {1,2,3,4}) ; // error: function print() does not take 2 arguments?
    

    Is it something obvious that is missing here? I would like to mix anything in the call to print() as it's declaration implies.

    Anybody?

    [Edit 2017-11-08]

    Somebody has suggested

     print("\nMy list is:\t", std::initializer_list<int>{1,2,3,4}) ;
    

    And to somewhat remedy the pain of this, I am crushed to admit I have defined this macro "helper"

    #define DBJ_IL(T,...) (std::initializer_list<T>{__VA_ARGS__})
    

    Usage:

    print("\nMy list is:\t", DBJ_IL(int,1,2,3,4)) ;
    

    But alas, MSVC 14.11.25503 (the latest as of time of this writing) can not compile this. With errors coming from

        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
    

    I am sure nobody want's the rest of the MSVC error dump ... Is it me or is it them?

    Doing the print() as generic lambda does not solve anything of course.

    /*
    forget templates
    */
    namespace dbj { namespace {
      auto print = [](auto... param)
      {
       if constexpr (sizeof...(param) > 0) {
        char dummy[sizeof...(param)] = { 
              (( std::cout << param), 0)... 
            };
         }
      };
    } }
    

    Even if one passes single and simple init list this wont compile with the same error as above ...

     dbj::print({1,2,3}) ; // msvc compilation error
    

    I know C++17 type deduction of init lists is strengthened and improved, but I can not see in there anything to help me understand is this doable at all?

    At last it seems it should be.

    0 讨论(0)
提交回复
热议问题