Problem with calling a variadic function template when passing brace initialiser list arguments

后端 未结 3 1791
一个人的身影
一个人的身影 2021-01-01 21:18

Consider this function template:

template 
void foo (std::tuple ... x);

This invocation works:

3条回答
  •  [愿得一人]
    2021-01-01 21:26

    I cannot use C++17 for this. A C++11-compatible solution is much preferred.

    With C++11 is a little more complicated (no std::index_sequence, no std::make_index_sequence) but, if you want maintain the variadic use of tuples... that is... if you substantially want something as

    foo (std::tuple ... ts)
    

    and if you accept to call a static method of a template struct, you can define a template struct that recursively inherit itself and, recursively, define a

    func ();
    func (K t0);
    func (K t0, K t1);
    func (K t0, K t1, K t2);
    

    where K is your

    using K = std::tuple;
    

    The following is a full compiling C++11 example

    #include 
    #include 
    
    using K = std::tuple;
    
    template 
    struct getTypeStruct
     { using type = T; };
    
    template 
    using getType = typename getTypeStruct::type;
    
    template 
    struct iList;
    
    template >
    struct foo;
    
    template 
    struct foo> : public foo>
     {
       using foo>::func;
    
       static void func (getType ... ts)
        { std::cout << sizeof...(ts) << std::endl; }
     };
    
    template 
    struct foo>
     {
       // fake func, for recursion ground case
       static void func ()
        { }
     };
    
    
    int main()
     {
       foo<>::func({1,'2',3.0}); // print 1
       foo<>::func({1,'2',3.0}, {4,'5',6.0}); // print 2
       foo<>::func({1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0});  // print 3
     }
    

    If you can use C++14, you can use std::make_index_sequence and std::index_sequence and the code become a little better, IMHO

    #include 
    #include 
    #include 
    
    using K = std::tuple;
    
    template 
    constexpr auto getIndexSequence (std::index_sequence is)
       -> decltype(is);
    
    template 
    using IndSeqFrom = decltype(getIndexSequence(std::make_index_sequence{}));
    
    template 
    struct getTypeStruct
     { using type = T; };
    
    template 
    using getType = typename getTypeStruct::type;
    
    template >
    struct foo;
    
    template 
    struct foo> : public foo
     {
       using foo::func;
    
       static void func (getType ... ts)
        { std::cout << sizeof...(ts) << std::endl; }
     };
    
    template <>
    struct foo<0, std::index_sequence<>>
     {
       static void func ()
        { std::cout << "0" << std::endl; }
     };
    
    int main()
     {
       foo<>::func({1,'2',3.0});  // print 1
       foo<>::func({1,'2',3.0}, {4,'5',6.0});  // print 2
       foo<>::func({1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0});  // print 3
     }
    

    It's a pity you can't use C++17 because in you could use variadic unsing and avoid at all recursive inheritance

    #include 
    #include 
    #include 
    
    using K = std::tuple;
    
    template 
    constexpr auto getIndexSequence (std::index_sequence is)
       -> decltype(is);
    
    template 
    using IndSeqFrom = decltype(getIndexSequence(std::make_index_sequence{}));
    
    template 
    struct getTypeStruct
     { using type = T; };
    
    template 
    using getType = typename getTypeStruct::type;
    
    template >
    struct bar;
    
    template 
    struct bar>
     {
       static void func (getType ... ts)
        { std::cout << sizeof...(ts) << std::endl; }
     };
    
    template >
    struct foo;
    
    template 
    struct foo> : public bar...
     { using bar::func...; };
    
    int main()
     {
       foo<>::func({1,'2',3.0});  // print 1
       foo<>::func({1,'2',3.0}, {4,'5',6.0});  // print 2
       foo<>::func({1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0});  // print 3
     }
    

提交回复
热议问题