single-line std::get std::index_sequence?












0















I have a std::tuple, and I want to unwrap the contents using std::index_sequence in order to call a variadic function template



Consider the following example code:



#include <iostream>
#include <tuple>

template<typename... Ts>
void foo(const std::string& s, Ts... ts)
{
std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
}

template<typename Tuple, std::size_t... Ixs>
void call_foo(const std::string& s, Tuple& t, std::index_sequence<Ixs...>)
{
foo(s, std::get<Ixs>(t)...);
}

template<typename... Ts>
struct Bar
{
Bar(Ts... ts) : t(ts...)
{ }

void do_it()
{
call_foo("hi", t, std::make_index_sequence<std::tuple_size<decltype(t)>::value>{});
}

std::tuple<Ts...> t;
};

template<typename... Ts> Bar<Ts...> make_bar(Ts... ts) { return Bar<Ts...>(ts...); }

int main ()
{
auto bar = make_bar(1, 'a', 2.3);
bar.do_it();
}


Note that I have to call through call_foo with my index_sequence in order to "unwrap" the index_sequence for calling std::get...



Is it possible to forego the intermediate call_foo function, and call foo directly?



That is, unwrap the tuple directly at the call-site?










share|improve this question




















  • 1





    If you have access to C++17: std::apply(foo, t);

    – Miles Budnek
    Jan 2 at 22:06











  • @MilesBudnek I've updated the question which adds an additional parameter to foo (other than the tuple elements) - apply would no longer work directly would it? I'd have to capture the other parameter in a lambda first, and then pass that to apply?

    – Steve Lorimer
    Jan 2 at 22:11






  • 1





    That or make a tuple that contains all the arguments. Perhaps std::tuple_cat is relevant?

    – Miles Budnek
    Jan 2 at 22:16


















0















I have a std::tuple, and I want to unwrap the contents using std::index_sequence in order to call a variadic function template



Consider the following example code:



#include <iostream>
#include <tuple>

template<typename... Ts>
void foo(const std::string& s, Ts... ts)
{
std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
}

template<typename Tuple, std::size_t... Ixs>
void call_foo(const std::string& s, Tuple& t, std::index_sequence<Ixs...>)
{
foo(s, std::get<Ixs>(t)...);
}

template<typename... Ts>
struct Bar
{
Bar(Ts... ts) : t(ts...)
{ }

void do_it()
{
call_foo("hi", t, std::make_index_sequence<std::tuple_size<decltype(t)>::value>{});
}

std::tuple<Ts...> t;
};

template<typename... Ts> Bar<Ts...> make_bar(Ts... ts) { return Bar<Ts...>(ts...); }

int main ()
{
auto bar = make_bar(1, 'a', 2.3);
bar.do_it();
}


Note that I have to call through call_foo with my index_sequence in order to "unwrap" the index_sequence for calling std::get...



Is it possible to forego the intermediate call_foo function, and call foo directly?



That is, unwrap the tuple directly at the call-site?










share|improve this question




















  • 1





    If you have access to C++17: std::apply(foo, t);

    – Miles Budnek
    Jan 2 at 22:06











  • @MilesBudnek I've updated the question which adds an additional parameter to foo (other than the tuple elements) - apply would no longer work directly would it? I'd have to capture the other parameter in a lambda first, and then pass that to apply?

    – Steve Lorimer
    Jan 2 at 22:11






  • 1





    That or make a tuple that contains all the arguments. Perhaps std::tuple_cat is relevant?

    – Miles Budnek
    Jan 2 at 22:16
















0












0








0








I have a std::tuple, and I want to unwrap the contents using std::index_sequence in order to call a variadic function template



Consider the following example code:



#include <iostream>
#include <tuple>

template<typename... Ts>
void foo(const std::string& s, Ts... ts)
{
std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
}

template<typename Tuple, std::size_t... Ixs>
void call_foo(const std::string& s, Tuple& t, std::index_sequence<Ixs...>)
{
foo(s, std::get<Ixs>(t)...);
}

template<typename... Ts>
struct Bar
{
Bar(Ts... ts) : t(ts...)
{ }

void do_it()
{
call_foo("hi", t, std::make_index_sequence<std::tuple_size<decltype(t)>::value>{});
}

std::tuple<Ts...> t;
};

template<typename... Ts> Bar<Ts...> make_bar(Ts... ts) { return Bar<Ts...>(ts...); }

int main ()
{
auto bar = make_bar(1, 'a', 2.3);
bar.do_it();
}


Note that I have to call through call_foo with my index_sequence in order to "unwrap" the index_sequence for calling std::get...



Is it possible to forego the intermediate call_foo function, and call foo directly?



That is, unwrap the tuple directly at the call-site?










share|improve this question
















I have a std::tuple, and I want to unwrap the contents using std::index_sequence in order to call a variadic function template



Consider the following example code:



#include <iostream>
#include <tuple>

template<typename... Ts>
void foo(const std::string& s, Ts... ts)
{
std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
}

template<typename Tuple, std::size_t... Ixs>
void call_foo(const std::string& s, Tuple& t, std::index_sequence<Ixs...>)
{
foo(s, std::get<Ixs>(t)...);
}

template<typename... Ts>
struct Bar
{
Bar(Ts... ts) : t(ts...)
{ }

void do_it()
{
call_foo("hi", t, std::make_index_sequence<std::tuple_size<decltype(t)>::value>{});
}

std::tuple<Ts...> t;
};

template<typename... Ts> Bar<Ts...> make_bar(Ts... ts) { return Bar<Ts...>(ts...); }

int main ()
{
auto bar = make_bar(1, 'a', 2.3);
bar.do_it();
}


Note that I have to call through call_foo with my index_sequence in order to "unwrap" the index_sequence for calling std::get...



Is it possible to forego the intermediate call_foo function, and call foo directly?



That is, unwrap the tuple directly at the call-site?







c++ stdtuple






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 2 at 22:32







Steve Lorimer

















asked Jan 2 at 22:04









Steve LorimerSteve Lorimer

12.8k1267142




12.8k1267142








  • 1





    If you have access to C++17: std::apply(foo, t);

    – Miles Budnek
    Jan 2 at 22:06











  • @MilesBudnek I've updated the question which adds an additional parameter to foo (other than the tuple elements) - apply would no longer work directly would it? I'd have to capture the other parameter in a lambda first, and then pass that to apply?

    – Steve Lorimer
    Jan 2 at 22:11






  • 1





    That or make a tuple that contains all the arguments. Perhaps std::tuple_cat is relevant?

    – Miles Budnek
    Jan 2 at 22:16
















  • 1





    If you have access to C++17: std::apply(foo, t);

    – Miles Budnek
    Jan 2 at 22:06











  • @MilesBudnek I've updated the question which adds an additional parameter to foo (other than the tuple elements) - apply would no longer work directly would it? I'd have to capture the other parameter in a lambda first, and then pass that to apply?

    – Steve Lorimer
    Jan 2 at 22:11






  • 1





    That or make a tuple that contains all the arguments. Perhaps std::tuple_cat is relevant?

    – Miles Budnek
    Jan 2 at 22:16










1




1





If you have access to C++17: std::apply(foo, t);

– Miles Budnek
Jan 2 at 22:06





If you have access to C++17: std::apply(foo, t);

– Miles Budnek
Jan 2 at 22:06













@MilesBudnek I've updated the question which adds an additional parameter to foo (other than the tuple elements) - apply would no longer work directly would it? I'd have to capture the other parameter in a lambda first, and then pass that to apply?

– Steve Lorimer
Jan 2 at 22:11





@MilesBudnek I've updated the question which adds an additional parameter to foo (other than the tuple elements) - apply would no longer work directly would it? I'd have to capture the other parameter in a lambda first, and then pass that to apply?

– Steve Lorimer
Jan 2 at 22:11




1




1





That or make a tuple that contains all the arguments. Perhaps std::tuple_cat is relevant?

– Miles Budnek
Jan 2 at 22:16







That or make a tuple that contains all the arguments. Perhaps std::tuple_cat is relevant?

– Miles Budnek
Jan 2 at 22:16














1 Answer
1






active

oldest

votes


















2














If you don't want to or can't use std::apply, I can suggest a few alternatives.



The snippets below are based on the previous revision of your question that didn't have the class Bar in it. The same solutions work for the new revision as well.



(1) You could replace call_foo with a C++20 lambda with an explicit template parameter list:



#include <cstddef>
#include <iostream>
#include <tuple>
#include <utility>

template<typename... Ts>
void foo(const std::string& s, Ts... ts)
{
std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
}

template<typename... Ts>
void bar(Ts... ts)
{
const std::string s = "hello world";
const auto t = std::make_tuple(ts...);

[&]<std::size_t ...I>(std::index_sequence<I...>)
{
foo(s, std::get<I>(t)...);
}
(std::make_index_sequence<std::tuple_size_v<decltype(t)>>{});
}

int main()
{
bar(1, 'a', 2.3);
}


Try it live



Unfortunately, GCC 8 currently seems to be the only major compiler that supports those.





(2) If your compiler doesn't have the new fancy lambdas, or you don't want to write the index_sequence boilerplate every time you need to expand the tuple, I suggest following:



#include <cstddef>
#include <iostream>
#include <tuple>
#include <utility>

template <std::size_t ...I, typename F> void with_sequence_impl(F &&func, std::index_sequence<I...>)
{
func(std::integral_constant<std::size_t, I>{}...);
}

template <std::size_t N, typename F> void with_sequence(F &&func)
{
with_sequence_impl(std::forward<F>(func), std::make_index_sequence<N>{});
}

template<typename... Ts>
void foo(const std::string& s, Ts... ts)
{
std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
}

template<typename... Ts>
void bar(Ts... ts)
{
const std::string s = "hello world";
const auto t = std::make_tuple(ts...);

with_sequence<std::tuple_size_v<decltype(t)>>([&](auto ... i)
{
foo(s, std::get<i.value>(t)...);
});
}

int main()
{
bar(1, 'a', 2.3);
}


Try it live






share|improve this answer


























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54013777%2fsingle-line-stdget-stdindex-sequence%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    If you don't want to or can't use std::apply, I can suggest a few alternatives.



    The snippets below are based on the previous revision of your question that didn't have the class Bar in it. The same solutions work for the new revision as well.



    (1) You could replace call_foo with a C++20 lambda with an explicit template parameter list:



    #include <cstddef>
    #include <iostream>
    #include <tuple>
    #include <utility>

    template<typename... Ts>
    void foo(const std::string& s, Ts... ts)
    {
    std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
    }

    template<typename... Ts>
    void bar(Ts... ts)
    {
    const std::string s = "hello world";
    const auto t = std::make_tuple(ts...);

    [&]<std::size_t ...I>(std::index_sequence<I...>)
    {
    foo(s, std::get<I>(t)...);
    }
    (std::make_index_sequence<std::tuple_size_v<decltype(t)>>{});
    }

    int main()
    {
    bar(1, 'a', 2.3);
    }


    Try it live



    Unfortunately, GCC 8 currently seems to be the only major compiler that supports those.





    (2) If your compiler doesn't have the new fancy lambdas, or you don't want to write the index_sequence boilerplate every time you need to expand the tuple, I suggest following:



    #include <cstddef>
    #include <iostream>
    #include <tuple>
    #include <utility>

    template <std::size_t ...I, typename F> void with_sequence_impl(F &&func, std::index_sequence<I...>)
    {
    func(std::integral_constant<std::size_t, I>{}...);
    }

    template <std::size_t N, typename F> void with_sequence(F &&func)
    {
    with_sequence_impl(std::forward<F>(func), std::make_index_sequence<N>{});
    }

    template<typename... Ts>
    void foo(const std::string& s, Ts... ts)
    {
    std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
    }

    template<typename... Ts>
    void bar(Ts... ts)
    {
    const std::string s = "hello world";
    const auto t = std::make_tuple(ts...);

    with_sequence<std::tuple_size_v<decltype(t)>>([&](auto ... i)
    {
    foo(s, std::get<i.value>(t)...);
    });
    }

    int main()
    {
    bar(1, 'a', 2.3);
    }


    Try it live






    share|improve this answer






























      2














      If you don't want to or can't use std::apply, I can suggest a few alternatives.



      The snippets below are based on the previous revision of your question that didn't have the class Bar in it. The same solutions work for the new revision as well.



      (1) You could replace call_foo with a C++20 lambda with an explicit template parameter list:



      #include <cstddef>
      #include <iostream>
      #include <tuple>
      #include <utility>

      template<typename... Ts>
      void foo(const std::string& s, Ts... ts)
      {
      std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
      }

      template<typename... Ts>
      void bar(Ts... ts)
      {
      const std::string s = "hello world";
      const auto t = std::make_tuple(ts...);

      [&]<std::size_t ...I>(std::index_sequence<I...>)
      {
      foo(s, std::get<I>(t)...);
      }
      (std::make_index_sequence<std::tuple_size_v<decltype(t)>>{});
      }

      int main()
      {
      bar(1, 'a', 2.3);
      }


      Try it live



      Unfortunately, GCC 8 currently seems to be the only major compiler that supports those.





      (2) If your compiler doesn't have the new fancy lambdas, or you don't want to write the index_sequence boilerplate every time you need to expand the tuple, I suggest following:



      #include <cstddef>
      #include <iostream>
      #include <tuple>
      #include <utility>

      template <std::size_t ...I, typename F> void with_sequence_impl(F &&func, std::index_sequence<I...>)
      {
      func(std::integral_constant<std::size_t, I>{}...);
      }

      template <std::size_t N, typename F> void with_sequence(F &&func)
      {
      with_sequence_impl(std::forward<F>(func), std::make_index_sequence<N>{});
      }

      template<typename... Ts>
      void foo(const std::string& s, Ts... ts)
      {
      std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
      }

      template<typename... Ts>
      void bar(Ts... ts)
      {
      const std::string s = "hello world";
      const auto t = std::make_tuple(ts...);

      with_sequence<std::tuple_size_v<decltype(t)>>([&](auto ... i)
      {
      foo(s, std::get<i.value>(t)...);
      });
      }

      int main()
      {
      bar(1, 'a', 2.3);
      }


      Try it live






      share|improve this answer




























        2












        2








        2







        If you don't want to or can't use std::apply, I can suggest a few alternatives.



        The snippets below are based on the previous revision of your question that didn't have the class Bar in it. The same solutions work for the new revision as well.



        (1) You could replace call_foo with a C++20 lambda with an explicit template parameter list:



        #include <cstddef>
        #include <iostream>
        #include <tuple>
        #include <utility>

        template<typename... Ts>
        void foo(const std::string& s, Ts... ts)
        {
        std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
        }

        template<typename... Ts>
        void bar(Ts... ts)
        {
        const std::string s = "hello world";
        const auto t = std::make_tuple(ts...);

        [&]<std::size_t ...I>(std::index_sequence<I...>)
        {
        foo(s, std::get<I>(t)...);
        }
        (std::make_index_sequence<std::tuple_size_v<decltype(t)>>{});
        }

        int main()
        {
        bar(1, 'a', 2.3);
        }


        Try it live



        Unfortunately, GCC 8 currently seems to be the only major compiler that supports those.





        (2) If your compiler doesn't have the new fancy lambdas, or you don't want to write the index_sequence boilerplate every time you need to expand the tuple, I suggest following:



        #include <cstddef>
        #include <iostream>
        #include <tuple>
        #include <utility>

        template <std::size_t ...I, typename F> void with_sequence_impl(F &&func, std::index_sequence<I...>)
        {
        func(std::integral_constant<std::size_t, I>{}...);
        }

        template <std::size_t N, typename F> void with_sequence(F &&func)
        {
        with_sequence_impl(std::forward<F>(func), std::make_index_sequence<N>{});
        }

        template<typename... Ts>
        void foo(const std::string& s, Ts... ts)
        {
        std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
        }

        template<typename... Ts>
        void bar(Ts... ts)
        {
        const std::string s = "hello world";
        const auto t = std::make_tuple(ts...);

        with_sequence<std::tuple_size_v<decltype(t)>>([&](auto ... i)
        {
        foo(s, std::get<i.value>(t)...);
        });
        }

        int main()
        {
        bar(1, 'a', 2.3);
        }


        Try it live






        share|improve this answer















        If you don't want to or can't use std::apply, I can suggest a few alternatives.



        The snippets below are based on the previous revision of your question that didn't have the class Bar in it. The same solutions work for the new revision as well.



        (1) You could replace call_foo with a C++20 lambda with an explicit template parameter list:



        #include <cstddef>
        #include <iostream>
        #include <tuple>
        #include <utility>

        template<typename... Ts>
        void foo(const std::string& s, Ts... ts)
        {
        std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
        }

        template<typename... Ts>
        void bar(Ts... ts)
        {
        const std::string s = "hello world";
        const auto t = std::make_tuple(ts...);

        [&]<std::size_t ...I>(std::index_sequence<I...>)
        {
        foo(s, std::get<I>(t)...);
        }
        (std::make_index_sequence<std::tuple_size_v<decltype(t)>>{});
        }

        int main()
        {
        bar(1, 'a', 2.3);
        }


        Try it live



        Unfortunately, GCC 8 currently seems to be the only major compiler that supports those.





        (2) If your compiler doesn't have the new fancy lambdas, or you don't want to write the index_sequence boilerplate every time you need to expand the tuple, I suggest following:



        #include <cstddef>
        #include <iostream>
        #include <tuple>
        #include <utility>

        template <std::size_t ...I, typename F> void with_sequence_impl(F &&func, std::index_sequence<I...>)
        {
        func(std::integral_constant<std::size_t, I>{}...);
        }

        template <std::size_t N, typename F> void with_sequence(F &&func)
        {
        with_sequence_impl(std::forward<F>(func), std::make_index_sequence<N>{});
        }

        template<typename... Ts>
        void foo(const std::string& s, Ts... ts)
        {
        std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " tsn";
        }

        template<typename... Ts>
        void bar(Ts... ts)
        {
        const std::string s = "hello world";
        const auto t = std::make_tuple(ts...);

        with_sequence<std::tuple_size_v<decltype(t)>>([&](auto ... i)
        {
        foo(s, std::get<i.value>(t)...);
        });
        }

        int main()
        {
        bar(1, 'a', 2.3);
        }


        Try it live







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jan 2 at 22:50

























        answered Jan 2 at 22:23









        HolyBlackCatHolyBlackCat

        17.2k33568




        17.2k33568
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54013777%2fsingle-line-stdget-stdindex-sequence%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

            Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

            A Topological Invariant for $pi_3(U(n))$