if constexpr with recursive parameter packsC++11 make_pair with specified template parameters doesn't compileDifference between `constexpr` and `const`C++: No matching function call when calling tuple_transpose functionIs array indexing constexpr or not ? GCC inconsistent?Enable method based on boolean template parameterImplementing is_constexpr_copiableC++ Template recursive to check type in std::tupleSize of std::array in class template depending on template parameterWhy recursive constexpr template value does not compile?Why did this error occur? c++ library build

Why does the Saturn V have standalone inter-stage rings?

Is there a way, while dragging, to "snap" to the nearest guide?

How does DC work with natural 20?

Is a single radon-daughter atom in air a solid?

Can humans ever directly see a few photons at a time? Can a human see a single photon?

Suggested order for Amazon Prime Doctor Who series

Hot coffee brewing solutions for deep woods camping

How large would a mega structure have to be to host 1 billion people indefinitely?

Can Ogre clerics use Purify Food and Drink on humanoid characters?

Methodology: Writing unit tests for another developer

When can you leave off “le/la” to say “it” in French?

Explain why a line can never intersect a plane in exactly two points.

Do I have to explain the mechanical superiority of the player-character within the fiction of the game?

Is it illegal to withhold someone's passport and green card in California?

How to model a twisted cylinder like this

What was the Shuttle Carrier Aircraft escape tunnel?

Why do some professors with PhDs leave their professorships to teach high school?

Find the C-factor of a vote

Are all instances of trolls turning to stone ultimately references back to Tolkien?

What is "industrial ethernet"?

What's currently blocking the construction of the wall between Mexico and the US?

Why are < or > required to use /dev/tcp

How to find the last non zero element in every column throughout dataframe?

What is the origin of Scooby-Doo's name?



if constexpr with recursive parameter packs


C++11 make_pair with specified template parameters doesn't compileDifference between `constexpr` and `const`C++: No matching function call when calling tuple_transpose functionIs array indexing constexpr or not ? GCC inconsistent?Enable method based on boolean template parameterImplementing is_constexpr_copiableC++ Template recursive to check type in std::tupleSize of std::array in class template depending on template parameterWhy recursive constexpr template value does not compile?Why did this error occur? c++ library build






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








7















I am trying to recursively run through a typelist so I can do some run-time code based on each type in the list. I would like to be able to recursively run through all the types in a tuple in a function in a struct (not in a function in the struct) without using "if constexpr" to terminate the recursion.



I have a snippet of code the shows the recursion working with constexpr.



#include <iostream>
#include <string>
#include <tuple>
template <typename ...Ts>
struct temp
using TypeList = std::tuple<Ts...>;
constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

void print_this()

_inner_print<_N,_N>();


template <std::size_t N, std::size_t MAX>
void _inner_print()

if constexpr ( N != 0 )

std::cout << "Call #"<<MAX-N<<std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
_inner_print<N-1, MAX>();



TypeList _mem;
;

int main()

std::string name;
temp<int, int, int> t1;
t1.print_this();



I would like to be able to do the same recursion with C++14, instead of C++17 w/ "if constexpr".



Thank you!










share|improve this question






















  • Something new to learn for me!

    – RC0993
    Jun 5 at 4:24











  • constexpr static std::size_t _N = sizeof...(Ts); is a simpler way to achieve the same... Be aware, though, that identifers starting with underscore followed by capital letter are reserved (as well as those containing two underscores).

    – Aconcagua
    Jun 5 at 5:03

















7















I am trying to recursively run through a typelist so I can do some run-time code based on each type in the list. I would like to be able to recursively run through all the types in a tuple in a function in a struct (not in a function in the struct) without using "if constexpr" to terminate the recursion.



I have a snippet of code the shows the recursion working with constexpr.



#include <iostream>
#include <string>
#include <tuple>
template <typename ...Ts>
struct temp
using TypeList = std::tuple<Ts...>;
constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

void print_this()

_inner_print<_N,_N>();


template <std::size_t N, std::size_t MAX>
void _inner_print()

if constexpr ( N != 0 )

std::cout << "Call #"<<MAX-N<<std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
_inner_print<N-1, MAX>();



TypeList _mem;
;

int main()

std::string name;
temp<int, int, int> t1;
t1.print_this();



I would like to be able to do the same recursion with C++14, instead of C++17 w/ "if constexpr".



Thank you!










share|improve this question






















  • Something new to learn for me!

    – RC0993
    Jun 5 at 4:24











  • constexpr static std::size_t _N = sizeof...(Ts); is a simpler way to achieve the same... Be aware, though, that identifers starting with underscore followed by capital letter are reserved (as well as those containing two underscores).

    – Aconcagua
    Jun 5 at 5:03













7












7








7


2






I am trying to recursively run through a typelist so I can do some run-time code based on each type in the list. I would like to be able to recursively run through all the types in a tuple in a function in a struct (not in a function in the struct) without using "if constexpr" to terminate the recursion.



I have a snippet of code the shows the recursion working with constexpr.



#include <iostream>
#include <string>
#include <tuple>
template <typename ...Ts>
struct temp
using TypeList = std::tuple<Ts...>;
constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

void print_this()

_inner_print<_N,_N>();


template <std::size_t N, std::size_t MAX>
void _inner_print()

if constexpr ( N != 0 )

std::cout << "Call #"<<MAX-N<<std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
_inner_print<N-1, MAX>();



TypeList _mem;
;

int main()

std::string name;
temp<int, int, int> t1;
t1.print_this();



I would like to be able to do the same recursion with C++14, instead of C++17 w/ "if constexpr".



Thank you!










share|improve this question














I am trying to recursively run through a typelist so I can do some run-time code based on each type in the list. I would like to be able to recursively run through all the types in a tuple in a function in a struct (not in a function in the struct) without using "if constexpr" to terminate the recursion.



I have a snippet of code the shows the recursion working with constexpr.



#include <iostream>
#include <string>
#include <tuple>
template <typename ...Ts>
struct temp
using TypeList = std::tuple<Ts...>;
constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

void print_this()

_inner_print<_N,_N>();


template <std::size_t N, std::size_t MAX>
void _inner_print()

if constexpr ( N != 0 )

std::cout << "Call #"<<MAX-N<<std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
_inner_print<N-1, MAX>();



TypeList _mem;
;

int main()

std::string name;
temp<int, int, int> t1;
t1.print_this();



I would like to be able to do the same recursion with C++14, instead of C++17 w/ "if constexpr".



Thank you!







c++






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jun 5 at 4:01









mrieramriera

725




725












  • Something new to learn for me!

    – RC0993
    Jun 5 at 4:24











  • constexpr static std::size_t _N = sizeof...(Ts); is a simpler way to achieve the same... Be aware, though, that identifers starting with underscore followed by capital letter are reserved (as well as those containing two underscores).

    – Aconcagua
    Jun 5 at 5:03

















  • Something new to learn for me!

    – RC0993
    Jun 5 at 4:24











  • constexpr static std::size_t _N = sizeof...(Ts); is a simpler way to achieve the same... Be aware, though, that identifers starting with underscore followed by capital letter are reserved (as well as those containing two underscores).

    – Aconcagua
    Jun 5 at 5:03
















Something new to learn for me!

– RC0993
Jun 5 at 4:24





Something new to learn for me!

– RC0993
Jun 5 at 4:24













constexpr static std::size_t _N = sizeof...(Ts); is a simpler way to achieve the same... Be aware, though, that identifers starting with underscore followed by capital letter are reserved (as well as those containing two underscores).

– Aconcagua
Jun 5 at 5:03





constexpr static std::size_t _N = sizeof...(Ts); is a simpler way to achieve the same... Be aware, though, that identifers starting with underscore followed by capital letter are reserved (as well as those containing two underscores).

– Aconcagua
Jun 5 at 5:03












4 Answers
4






active

oldest

votes


















7














The trick is to use index_sequence.



Here is a C++14 working solution, improved using @MartinMorterol suggestion.



// -*- compile-command: "g++ -Wall -std=c++14 poub.cpp; ./a.out"; -*-
#include <iostream>
#include <string>
#include <tuple>
#include <type_traits>

template <typename... Ts>
struct temp

using TypeList = std::tuple<Ts...>;
constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

void print_this() _inner_print(std::make_index_sequence<_N>());

template <std::size_t... IDX>
void _inner_print(std::index_sequence<IDX...>)

auto dummy = 0, (_inner_print<IDX>(),0)...;
(void)dummy;


template <std::size_t IDX>
void _inner_print()

std::cout << "nCall #" << IDX
<< " sizeof " << sizeof(std::get<IDX>(_mem));


TypeList _mem;
;

int main()

std::string name;
temp<int, double, char> t1;
t1.print_this();



which prints:



g++ -Wall -std=c++14 poub.cpp; ./a.out

Call #0 sizeof 4
Call #1 sizeof 8
Call #2 sizeof 1



My initial answer (using recursion)



// -*- compile-command: "g++ -std=c++14 poub.cpp; ./a.out"; -*-
#include <iostream>
#include <string>
#include <tuple>
#include <type_traits>

template <typename... Ts>
struct temp

using TypeList = std::tuple<Ts...>;
constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

void print_this() _inner_print(std::make_index_sequence<_N>());

template <std::size_t... IDX>
void _inner_print(std::index_sequence<IDX...>)

_inner_print(std::integral_constant<std::size_t, IDX>()...);


template <std::size_t HEAD_IDX, typename... TAIL>
void _inner_print(std::integral_constant<std::size_t, HEAD_IDX>, TAIL... tail)

std::cout << "nCall #" << HEAD_IDX
<< " sizeof " << sizeof(std::get<HEAD_IDX>(_mem));

// whatever you want HERE ...

_inner_print(tail...);

void _inner_print();

TypeList _mem;
;

int main()

std::string name;
temp<int, double, char> t1;
t1.print_this();






share|improve this answer

























  • You may use the trick auto dummy = (_inner_print<IDX>(),0)...; to do your C++17 code in C++14. And since your solution don't recurse, it probably compile faster !

    – Martin Morterol
    Jun 5 at 5:29











  • @MartinMorterol, great, that works! Are you ok if I update my answer using your suggestion?

    – Picaud Vincent
    Jun 5 at 5:36











  • Yeah sure! Better stack answer => better C++ developer ;)

    – Martin Morterol
    Jun 5 at 6:33












  • @MartinMorterol thanks for this C++14 trick I did not know :)

    – Picaud Vincent
    Jun 5 at 6:35






  • 1





    +1 for the array expansion trick. It's an important idiom to get used to when working with variadics, as it simplifies code quite a bit compared to recursion. The important point to remember is that the order of function calls is guaranteed here, which allows scheduling functions with side-effects; it would not be the case with a regular function call as the order of evaluation of function arguments is not guaranteed (and typically MSVC and gcc use different orders).

    – Matthieu M.
    Jun 5 at 15:01


















5














If you can change your _inner_print function to a class, you can make use of a partial specialization to end the recursion:



template <std::size_t N, std::size_t MAX>
struct _inner_print

_inner_print()

std::cout << "Call #"<<MAX-N<<std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
_inner_print<N-1, MAX>();

;

template <std::size_t MAX> struct _inner_print<0, MAX> ;


Rather than calling _inner_print() as a function, it becomes a declaration for an unnamed temporary, invoking the constructor that performs your output.






share|improve this answer

























  • perhaps constexpr _inner_print()

    – Swift - Friday Pie
    Jun 5 at 4:38



















4














You should use partial specialization. But you can't do this with a function.



You should use a struct to do the trick.



#include <iostream>
#include <string>
#include <tuple>

template <std::size_t N, std::size_t MAX, class T>
struct inner_print_impl
static void run(const T& caller)


std::cout << "Call #"<<MAX-N<< " " << caller.a << std::endl;
////////////////////////
/* other dynamic code */
////////////////////////
inner_print_impl<N-1, MAX , T>::run(caller);

;

template < std::size_t MAX, class T>
struct inner_print_impl<0, MAX , T>
static void run(const T& caller)


std::cout << "Call #"<<MAX<< " " << caller.a << std::endl;
////////////////////////
/* other dynamic code */
////////////////////////

// no recursion

;


template <typename ...Ts>
struct temp

using TypeList = std::tuple<Ts...>;
constexpr static std::size_t N_ = std::tuple_size<TypeList>::value;

template <std::size_t N, std::size_t MAX, class T>
friend struct inner_print_impl;
void print_this()

inner_print_impl<N_,N_, temp<Ts...> >::run(*this);


TypeList _mem;

private :

int a ; // test acces
;

int main()

std::string name;
temp<int, int, int> t1;
t1.print_this();



Note :



  1. If you need to acces to a private membre, you will need to pass *this to the call and add the new struct as friend of your class

  2. In my code, I have a duplication on the /* other dynamic code */ part. You may :

    • Use a function

    • make your template parameter a int instead of size_t and stop at -1 rather than 0


PS :



I don't get the part




in a tuple in a function in a struct (not in a function in the struct)




I hope I didn't miss something



Edit :



My code do one more iteration than your, you may just empty this :



template < std::size_t MAX, class T>
struct inner_print_impl<0, MAX , T>
static void run(const T& caller)


;


And you don't display for the 0 case.






share|improve this answer
































    0














    template<class Integral, Integral N>
    auto dispatch( std::integral_constant<Integral, N> )
    return [](auto&&...args)
    return std::get<N>( std::forward_as_tuple( decltype(args)(args)... ) );
    ;

    template<std::size_t N>
    auto dispatch()
    return dispatch( std::integral_constant<std::size_t, N> );



    this little beauty gives you much of the magic of if constexpr in c++14.



    template <std::size_t N, std::size_t MAX>
    void _inner_print()
    dispatch( std::integral_constant<bool, N==0> )
    (
    // 0, aka false branch:
    [&](auto Nval)
    std::cout << "Call #"<<MAX-Nval<<std::endl;
    ////////////////////////
    /* other dynamic code */
    ////////////////////////
    _inner_print<Nval-1, MAX>();
    ,
    // 1, aka true branch:
    [](auto&&)
    )( std::integral_constant<std::size_t, N> );



    Live example.



    Note that we have to pass in the N via an argument to the lambda, because we want the validity of the lambda's body to vary based on its argument, which is only passed to the right one.




    Alternatively, you can use an overload helper:



    template<class T0, class...Ts>
    struct overloaded;
    template<class Lhs, class Rhs, class...Ts>
    struct overloaded<Lhs, Rhs, Ts...>:
    overloaded<Lhs>, overloaded<Rhs,Ts...>

    using overloaded<Lhs>::operator();
    using overloaded<Rhs,Ts...>::operator();
    template<class A0, class...As>
    explicit overloaded(A0&&a0, As&&...as) :
    overloaded<Lhs>(std::forward<A0>(a0)),
    overloaded<Rhs,Ts...>( std::forward<As>(as)... )

    overloaded(overloaded const&)=default;
    overloaded(overloaded &&)=default;
    overloaded& operator=(overloaded const&)=default;
    overloaded& operator=(overloaded &&)=default;
    ;
    template<class T0>
    struct overloaded<T0> : T0
    using T0::operator();
    template<class A0>
    explicit overloaded(A0&&a0):
    T0(std::forward<A0>(a0))


    overloaded(overloaded const&)=default;
    overloaded(overloaded &&)=default;
    overloaded& operator=(overloaded const&)=default;
    overloaded& operator=(overloaded &&)=default;
    ;
    template<class R, class...Args>
    struct overloaded<R(*)(Args...)>
    R operator()(Args... args) const
    return pf(std::forward<Args>(args)...);

    R(*pf)(Args...);
    overloaded( R(*f)(Args...) ):pf(f)

    overloaded(overloaded const&)=default;
    overloaded(overloaded &&)=default;
    overloaded& operator=(overloaded const&)=default;
    overloaded& operator=(overloaded &&)=default;
    ;
    template<class...Args>
    auto overload( Args&&...args )
    return overloaded<std::decay_t<Args>...>(
    std::forward<Args>(args)...
    );



    Here is how you can use overloaded:



    template <std::size_t N, std::size_t MAX>
    void _inner_print()

    std::integral_constant<std::size_t, N> index;
    overload(
    [](std::integral_constant<std::size_t, 0>) ,
    [&](auto index)
    std::cout << "Call #"<<MAX-index<<std::endl;
    ////////////////////////
    /* other dynamic code */
    ////////////////////////
    _inner_print<index-1, MAX>();

    )(index);



    note that the rule is that the only-sometimes-compiling dynamic code must depend on the auto arguments to the lambda.



    Live example.






    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%2f56454091%2fif-constexpr-with-recursive-parameter-packs%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      7














      The trick is to use index_sequence.



      Here is a C++14 working solution, improved using @MartinMorterol suggestion.



      // -*- compile-command: "g++ -Wall -std=c++14 poub.cpp; ./a.out"; -*-
      #include <iostream>
      #include <string>
      #include <tuple>
      #include <type_traits>

      template <typename... Ts>
      struct temp

      using TypeList = std::tuple<Ts...>;
      constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

      void print_this() _inner_print(std::make_index_sequence<_N>());

      template <std::size_t... IDX>
      void _inner_print(std::index_sequence<IDX...>)

      auto dummy = 0, (_inner_print<IDX>(),0)...;
      (void)dummy;


      template <std::size_t IDX>
      void _inner_print()

      std::cout << "nCall #" << IDX
      << " sizeof " << sizeof(std::get<IDX>(_mem));


      TypeList _mem;
      ;

      int main()

      std::string name;
      temp<int, double, char> t1;
      t1.print_this();



      which prints:



      g++ -Wall -std=c++14 poub.cpp; ./a.out

      Call #0 sizeof 4
      Call #1 sizeof 8
      Call #2 sizeof 1



      My initial answer (using recursion)



      // -*- compile-command: "g++ -std=c++14 poub.cpp; ./a.out"; -*-
      #include <iostream>
      #include <string>
      #include <tuple>
      #include <type_traits>

      template <typename... Ts>
      struct temp

      using TypeList = std::tuple<Ts...>;
      constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

      void print_this() _inner_print(std::make_index_sequence<_N>());

      template <std::size_t... IDX>
      void _inner_print(std::index_sequence<IDX...>)

      _inner_print(std::integral_constant<std::size_t, IDX>()...);


      template <std::size_t HEAD_IDX, typename... TAIL>
      void _inner_print(std::integral_constant<std::size_t, HEAD_IDX>, TAIL... tail)

      std::cout << "nCall #" << HEAD_IDX
      << " sizeof " << sizeof(std::get<HEAD_IDX>(_mem));

      // whatever you want HERE ...

      _inner_print(tail...);

      void _inner_print();

      TypeList _mem;
      ;

      int main()

      std::string name;
      temp<int, double, char> t1;
      t1.print_this();






      share|improve this answer

























      • You may use the trick auto dummy = (_inner_print<IDX>(),0)...; to do your C++17 code in C++14. And since your solution don't recurse, it probably compile faster !

        – Martin Morterol
        Jun 5 at 5:29











      • @MartinMorterol, great, that works! Are you ok if I update my answer using your suggestion?

        – Picaud Vincent
        Jun 5 at 5:36











      • Yeah sure! Better stack answer => better C++ developer ;)

        – Martin Morterol
        Jun 5 at 6:33












      • @MartinMorterol thanks for this C++14 trick I did not know :)

        – Picaud Vincent
        Jun 5 at 6:35






      • 1





        +1 for the array expansion trick. It's an important idiom to get used to when working with variadics, as it simplifies code quite a bit compared to recursion. The important point to remember is that the order of function calls is guaranteed here, which allows scheduling functions with side-effects; it would not be the case with a regular function call as the order of evaluation of function arguments is not guaranteed (and typically MSVC and gcc use different orders).

        – Matthieu M.
        Jun 5 at 15:01















      7














      The trick is to use index_sequence.



      Here is a C++14 working solution, improved using @MartinMorterol suggestion.



      // -*- compile-command: "g++ -Wall -std=c++14 poub.cpp; ./a.out"; -*-
      #include <iostream>
      #include <string>
      #include <tuple>
      #include <type_traits>

      template <typename... Ts>
      struct temp

      using TypeList = std::tuple<Ts...>;
      constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

      void print_this() _inner_print(std::make_index_sequence<_N>());

      template <std::size_t... IDX>
      void _inner_print(std::index_sequence<IDX...>)

      auto dummy = 0, (_inner_print<IDX>(),0)...;
      (void)dummy;


      template <std::size_t IDX>
      void _inner_print()

      std::cout << "nCall #" << IDX
      << " sizeof " << sizeof(std::get<IDX>(_mem));


      TypeList _mem;
      ;

      int main()

      std::string name;
      temp<int, double, char> t1;
      t1.print_this();



      which prints:



      g++ -Wall -std=c++14 poub.cpp; ./a.out

      Call #0 sizeof 4
      Call #1 sizeof 8
      Call #2 sizeof 1



      My initial answer (using recursion)



      // -*- compile-command: "g++ -std=c++14 poub.cpp; ./a.out"; -*-
      #include <iostream>
      #include <string>
      #include <tuple>
      #include <type_traits>

      template <typename... Ts>
      struct temp

      using TypeList = std::tuple<Ts...>;
      constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

      void print_this() _inner_print(std::make_index_sequence<_N>());

      template <std::size_t... IDX>
      void _inner_print(std::index_sequence<IDX...>)

      _inner_print(std::integral_constant<std::size_t, IDX>()...);


      template <std::size_t HEAD_IDX, typename... TAIL>
      void _inner_print(std::integral_constant<std::size_t, HEAD_IDX>, TAIL... tail)

      std::cout << "nCall #" << HEAD_IDX
      << " sizeof " << sizeof(std::get<HEAD_IDX>(_mem));

      // whatever you want HERE ...

      _inner_print(tail...);

      void _inner_print();

      TypeList _mem;
      ;

      int main()

      std::string name;
      temp<int, double, char> t1;
      t1.print_this();






      share|improve this answer

























      • You may use the trick auto dummy = (_inner_print<IDX>(),0)...; to do your C++17 code in C++14. And since your solution don't recurse, it probably compile faster !

        – Martin Morterol
        Jun 5 at 5:29











      • @MartinMorterol, great, that works! Are you ok if I update my answer using your suggestion?

        – Picaud Vincent
        Jun 5 at 5:36











      • Yeah sure! Better stack answer => better C++ developer ;)

        – Martin Morterol
        Jun 5 at 6:33












      • @MartinMorterol thanks for this C++14 trick I did not know :)

        – Picaud Vincent
        Jun 5 at 6:35






      • 1





        +1 for the array expansion trick. It's an important idiom to get used to when working with variadics, as it simplifies code quite a bit compared to recursion. The important point to remember is that the order of function calls is guaranteed here, which allows scheduling functions with side-effects; it would not be the case with a regular function call as the order of evaluation of function arguments is not guaranteed (and typically MSVC and gcc use different orders).

        – Matthieu M.
        Jun 5 at 15:01













      7












      7








      7







      The trick is to use index_sequence.



      Here is a C++14 working solution, improved using @MartinMorterol suggestion.



      // -*- compile-command: "g++ -Wall -std=c++14 poub.cpp; ./a.out"; -*-
      #include <iostream>
      #include <string>
      #include <tuple>
      #include <type_traits>

      template <typename... Ts>
      struct temp

      using TypeList = std::tuple<Ts...>;
      constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

      void print_this() _inner_print(std::make_index_sequence<_N>());

      template <std::size_t... IDX>
      void _inner_print(std::index_sequence<IDX...>)

      auto dummy = 0, (_inner_print<IDX>(),0)...;
      (void)dummy;


      template <std::size_t IDX>
      void _inner_print()

      std::cout << "nCall #" << IDX
      << " sizeof " << sizeof(std::get<IDX>(_mem));


      TypeList _mem;
      ;

      int main()

      std::string name;
      temp<int, double, char> t1;
      t1.print_this();



      which prints:



      g++ -Wall -std=c++14 poub.cpp; ./a.out

      Call #0 sizeof 4
      Call #1 sizeof 8
      Call #2 sizeof 1



      My initial answer (using recursion)



      // -*- compile-command: "g++ -std=c++14 poub.cpp; ./a.out"; -*-
      #include <iostream>
      #include <string>
      #include <tuple>
      #include <type_traits>

      template <typename... Ts>
      struct temp

      using TypeList = std::tuple<Ts...>;
      constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

      void print_this() _inner_print(std::make_index_sequence<_N>());

      template <std::size_t... IDX>
      void _inner_print(std::index_sequence<IDX...>)

      _inner_print(std::integral_constant<std::size_t, IDX>()...);


      template <std::size_t HEAD_IDX, typename... TAIL>
      void _inner_print(std::integral_constant<std::size_t, HEAD_IDX>, TAIL... tail)

      std::cout << "nCall #" << HEAD_IDX
      << " sizeof " << sizeof(std::get<HEAD_IDX>(_mem));

      // whatever you want HERE ...

      _inner_print(tail...);

      void _inner_print();

      TypeList _mem;
      ;

      int main()

      std::string name;
      temp<int, double, char> t1;
      t1.print_this();






      share|improve this answer















      The trick is to use index_sequence.



      Here is a C++14 working solution, improved using @MartinMorterol suggestion.



      // -*- compile-command: "g++ -Wall -std=c++14 poub.cpp; ./a.out"; -*-
      #include <iostream>
      #include <string>
      #include <tuple>
      #include <type_traits>

      template <typename... Ts>
      struct temp

      using TypeList = std::tuple<Ts...>;
      constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

      void print_this() _inner_print(std::make_index_sequence<_N>());

      template <std::size_t... IDX>
      void _inner_print(std::index_sequence<IDX...>)

      auto dummy = 0, (_inner_print<IDX>(),0)...;
      (void)dummy;


      template <std::size_t IDX>
      void _inner_print()

      std::cout << "nCall #" << IDX
      << " sizeof " << sizeof(std::get<IDX>(_mem));


      TypeList _mem;
      ;

      int main()

      std::string name;
      temp<int, double, char> t1;
      t1.print_this();



      which prints:



      g++ -Wall -std=c++14 poub.cpp; ./a.out

      Call #0 sizeof 4
      Call #1 sizeof 8
      Call #2 sizeof 1



      My initial answer (using recursion)



      // -*- compile-command: "g++ -std=c++14 poub.cpp; ./a.out"; -*-
      #include <iostream>
      #include <string>
      #include <tuple>
      #include <type_traits>

      template <typename... Ts>
      struct temp

      using TypeList = std::tuple<Ts...>;
      constexpr static std::size_t _N = std::tuple_size<TypeList>::value;

      void print_this() _inner_print(std::make_index_sequence<_N>());

      template <std::size_t... IDX>
      void _inner_print(std::index_sequence<IDX...>)

      _inner_print(std::integral_constant<std::size_t, IDX>()...);


      template <std::size_t HEAD_IDX, typename... TAIL>
      void _inner_print(std::integral_constant<std::size_t, HEAD_IDX>, TAIL... tail)

      std::cout << "nCall #" << HEAD_IDX
      << " sizeof " << sizeof(std::get<HEAD_IDX>(_mem));

      // whatever you want HERE ...

      _inner_print(tail...);

      void _inner_print();

      TypeList _mem;
      ;

      int main()

      std::string name;
      temp<int, double, char> t1;
      t1.print_this();







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Jun 5 at 9:53









      Jarod42

      124k12109194




      124k12109194










      answered Jun 5 at 5:07









      Picaud VincentPicaud Vincent

      4,25811138




      4,25811138












      • You may use the trick auto dummy = (_inner_print<IDX>(),0)...; to do your C++17 code in C++14. And since your solution don't recurse, it probably compile faster !

        – Martin Morterol
        Jun 5 at 5:29











      • @MartinMorterol, great, that works! Are you ok if I update my answer using your suggestion?

        – Picaud Vincent
        Jun 5 at 5:36











      • Yeah sure! Better stack answer => better C++ developer ;)

        – Martin Morterol
        Jun 5 at 6:33












      • @MartinMorterol thanks for this C++14 trick I did not know :)

        – Picaud Vincent
        Jun 5 at 6:35






      • 1





        +1 for the array expansion trick. It's an important idiom to get used to when working with variadics, as it simplifies code quite a bit compared to recursion. The important point to remember is that the order of function calls is guaranteed here, which allows scheduling functions with side-effects; it would not be the case with a regular function call as the order of evaluation of function arguments is not guaranteed (and typically MSVC and gcc use different orders).

        – Matthieu M.
        Jun 5 at 15:01

















      • You may use the trick auto dummy = (_inner_print<IDX>(),0)...; to do your C++17 code in C++14. And since your solution don't recurse, it probably compile faster !

        – Martin Morterol
        Jun 5 at 5:29











      • @MartinMorterol, great, that works! Are you ok if I update my answer using your suggestion?

        – Picaud Vincent
        Jun 5 at 5:36











      • Yeah sure! Better stack answer => better C++ developer ;)

        – Martin Morterol
        Jun 5 at 6:33












      • @MartinMorterol thanks for this C++14 trick I did not know :)

        – Picaud Vincent
        Jun 5 at 6:35






      • 1





        +1 for the array expansion trick. It's an important idiom to get used to when working with variadics, as it simplifies code quite a bit compared to recursion. The important point to remember is that the order of function calls is guaranteed here, which allows scheduling functions with side-effects; it would not be the case with a regular function call as the order of evaluation of function arguments is not guaranteed (and typically MSVC and gcc use different orders).

        – Matthieu M.
        Jun 5 at 15:01
















      You may use the trick auto dummy = (_inner_print<IDX>(),0)...; to do your C++17 code in C++14. And since your solution don't recurse, it probably compile faster !

      – Martin Morterol
      Jun 5 at 5:29





      You may use the trick auto dummy = (_inner_print<IDX>(),0)...; to do your C++17 code in C++14. And since your solution don't recurse, it probably compile faster !

      – Martin Morterol
      Jun 5 at 5:29













      @MartinMorterol, great, that works! Are you ok if I update my answer using your suggestion?

      – Picaud Vincent
      Jun 5 at 5:36





      @MartinMorterol, great, that works! Are you ok if I update my answer using your suggestion?

      – Picaud Vincent
      Jun 5 at 5:36













      Yeah sure! Better stack answer => better C++ developer ;)

      – Martin Morterol
      Jun 5 at 6:33






      Yeah sure! Better stack answer => better C++ developer ;)

      – Martin Morterol
      Jun 5 at 6:33














      @MartinMorterol thanks for this C++14 trick I did not know :)

      – Picaud Vincent
      Jun 5 at 6:35





      @MartinMorterol thanks for this C++14 trick I did not know :)

      – Picaud Vincent
      Jun 5 at 6:35




      1




      1





      +1 for the array expansion trick. It's an important idiom to get used to when working with variadics, as it simplifies code quite a bit compared to recursion. The important point to remember is that the order of function calls is guaranteed here, which allows scheduling functions with side-effects; it would not be the case with a regular function call as the order of evaluation of function arguments is not guaranteed (and typically MSVC and gcc use different orders).

      – Matthieu M.
      Jun 5 at 15:01





      +1 for the array expansion trick. It's an important idiom to get used to when working with variadics, as it simplifies code quite a bit compared to recursion. The important point to remember is that the order of function calls is guaranteed here, which allows scheduling functions with side-effects; it would not be the case with a regular function call as the order of evaluation of function arguments is not guaranteed (and typically MSVC and gcc use different orders).

      – Matthieu M.
      Jun 5 at 15:01













      5














      If you can change your _inner_print function to a class, you can make use of a partial specialization to end the recursion:



      template <std::size_t N, std::size_t MAX>
      struct _inner_print

      _inner_print()

      std::cout << "Call #"<<MAX-N<<std::endl;
      ////////////////////////
      /* other dynamic code */
      ////////////////////////
      _inner_print<N-1, MAX>();

      ;

      template <std::size_t MAX> struct _inner_print<0, MAX> ;


      Rather than calling _inner_print() as a function, it becomes a declaration for an unnamed temporary, invoking the constructor that performs your output.






      share|improve this answer

























      • perhaps constexpr _inner_print()

        – Swift - Friday Pie
        Jun 5 at 4:38
















      5














      If you can change your _inner_print function to a class, you can make use of a partial specialization to end the recursion:



      template <std::size_t N, std::size_t MAX>
      struct _inner_print

      _inner_print()

      std::cout << "Call #"<<MAX-N<<std::endl;
      ////////////////////////
      /* other dynamic code */
      ////////////////////////
      _inner_print<N-1, MAX>();

      ;

      template <std::size_t MAX> struct _inner_print<0, MAX> ;


      Rather than calling _inner_print() as a function, it becomes a declaration for an unnamed temporary, invoking the constructor that performs your output.






      share|improve this answer

























      • perhaps constexpr _inner_print()

        – Swift - Friday Pie
        Jun 5 at 4:38














      5












      5








      5







      If you can change your _inner_print function to a class, you can make use of a partial specialization to end the recursion:



      template <std::size_t N, std::size_t MAX>
      struct _inner_print

      _inner_print()

      std::cout << "Call #"<<MAX-N<<std::endl;
      ////////////////////////
      /* other dynamic code */
      ////////////////////////
      _inner_print<N-1, MAX>();

      ;

      template <std::size_t MAX> struct _inner_print<0, MAX> ;


      Rather than calling _inner_print() as a function, it becomes a declaration for an unnamed temporary, invoking the constructor that performs your output.






      share|improve this answer















      If you can change your _inner_print function to a class, you can make use of a partial specialization to end the recursion:



      template <std::size_t N, std::size_t MAX>
      struct _inner_print

      _inner_print()

      std::cout << "Call #"<<MAX-N<<std::endl;
      ////////////////////////
      /* other dynamic code */
      ////////////////////////
      _inner_print<N-1, MAX>();

      ;

      template <std::size_t MAX> struct _inner_print<0, MAX> ;


      Rather than calling _inner_print() as a function, it becomes a declaration for an unnamed temporary, invoking the constructor that performs your output.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Jun 5 at 18:02

























      answered Jun 5 at 4:27









      1201ProgramAlarm1201ProgramAlarm

      20.2k72741




      20.2k72741












      • perhaps constexpr _inner_print()

        – Swift - Friday Pie
        Jun 5 at 4:38


















      • perhaps constexpr _inner_print()

        – Swift - Friday Pie
        Jun 5 at 4:38

















      perhaps constexpr _inner_print()

      – Swift - Friday Pie
      Jun 5 at 4:38






      perhaps constexpr _inner_print()

      – Swift - Friday Pie
      Jun 5 at 4:38












      4














      You should use partial specialization. But you can't do this with a function.



      You should use a struct to do the trick.



      #include <iostream>
      #include <string>
      #include <tuple>

      template <std::size_t N, std::size_t MAX, class T>
      struct inner_print_impl
      static void run(const T& caller)


      std::cout << "Call #"<<MAX-N<< " " << caller.a << std::endl;
      ////////////////////////
      /* other dynamic code */
      ////////////////////////
      inner_print_impl<N-1, MAX , T>::run(caller);

      ;

      template < std::size_t MAX, class T>
      struct inner_print_impl<0, MAX , T>
      static void run(const T& caller)


      std::cout << "Call #"<<MAX<< " " << caller.a << std::endl;
      ////////////////////////
      /* other dynamic code */
      ////////////////////////

      // no recursion

      ;


      template <typename ...Ts>
      struct temp

      using TypeList = std::tuple<Ts...>;
      constexpr static std::size_t N_ = std::tuple_size<TypeList>::value;

      template <std::size_t N, std::size_t MAX, class T>
      friend struct inner_print_impl;
      void print_this()

      inner_print_impl<N_,N_, temp<Ts...> >::run(*this);


      TypeList _mem;

      private :

      int a ; // test acces
      ;

      int main()

      std::string name;
      temp<int, int, int> t1;
      t1.print_this();



      Note :



      1. If you need to acces to a private membre, you will need to pass *this to the call and add the new struct as friend of your class

      2. In my code, I have a duplication on the /* other dynamic code */ part. You may :

        • Use a function

        • make your template parameter a int instead of size_t and stop at -1 rather than 0


      PS :



      I don't get the part




      in a tuple in a function in a struct (not in a function in the struct)




      I hope I didn't miss something



      Edit :



      My code do one more iteration than your, you may just empty this :



      template < std::size_t MAX, class T>
      struct inner_print_impl<0, MAX , T>
      static void run(const T& caller)


      ;


      And you don't display for the 0 case.






      share|improve this answer





























        4














        You should use partial specialization. But you can't do this with a function.



        You should use a struct to do the trick.



        #include <iostream>
        #include <string>
        #include <tuple>

        template <std::size_t N, std::size_t MAX, class T>
        struct inner_print_impl
        static void run(const T& caller)


        std::cout << "Call #"<<MAX-N<< " " << caller.a << std::endl;
        ////////////////////////
        /* other dynamic code */
        ////////////////////////
        inner_print_impl<N-1, MAX , T>::run(caller);

        ;

        template < std::size_t MAX, class T>
        struct inner_print_impl<0, MAX , T>
        static void run(const T& caller)


        std::cout << "Call #"<<MAX<< " " << caller.a << std::endl;
        ////////////////////////
        /* other dynamic code */
        ////////////////////////

        // no recursion

        ;


        template <typename ...Ts>
        struct temp

        using TypeList = std::tuple<Ts...>;
        constexpr static std::size_t N_ = std::tuple_size<TypeList>::value;

        template <std::size_t N, std::size_t MAX, class T>
        friend struct inner_print_impl;
        void print_this()

        inner_print_impl<N_,N_, temp<Ts...> >::run(*this);


        TypeList _mem;

        private :

        int a ; // test acces
        ;

        int main()

        std::string name;
        temp<int, int, int> t1;
        t1.print_this();



        Note :



        1. If you need to acces to a private membre, you will need to pass *this to the call and add the new struct as friend of your class

        2. In my code, I have a duplication on the /* other dynamic code */ part. You may :

          • Use a function

          • make your template parameter a int instead of size_t and stop at -1 rather than 0


        PS :



        I don't get the part




        in a tuple in a function in a struct (not in a function in the struct)




        I hope I didn't miss something



        Edit :



        My code do one more iteration than your, you may just empty this :



        template < std::size_t MAX, class T>
        struct inner_print_impl<0, MAX , T>
        static void run(const T& caller)


        ;


        And you don't display for the 0 case.






        share|improve this answer



























          4












          4








          4







          You should use partial specialization. But you can't do this with a function.



          You should use a struct to do the trick.



          #include <iostream>
          #include <string>
          #include <tuple>

          template <std::size_t N, std::size_t MAX, class T>
          struct inner_print_impl
          static void run(const T& caller)


          std::cout << "Call #"<<MAX-N<< " " << caller.a << std::endl;
          ////////////////////////
          /* other dynamic code */
          ////////////////////////
          inner_print_impl<N-1, MAX , T>::run(caller);

          ;

          template < std::size_t MAX, class T>
          struct inner_print_impl<0, MAX , T>
          static void run(const T& caller)


          std::cout << "Call #"<<MAX<< " " << caller.a << std::endl;
          ////////////////////////
          /* other dynamic code */
          ////////////////////////

          // no recursion

          ;


          template <typename ...Ts>
          struct temp

          using TypeList = std::tuple<Ts...>;
          constexpr static std::size_t N_ = std::tuple_size<TypeList>::value;

          template <std::size_t N, std::size_t MAX, class T>
          friend struct inner_print_impl;
          void print_this()

          inner_print_impl<N_,N_, temp<Ts...> >::run(*this);


          TypeList _mem;

          private :

          int a ; // test acces
          ;

          int main()

          std::string name;
          temp<int, int, int> t1;
          t1.print_this();



          Note :



          1. If you need to acces to a private membre, you will need to pass *this to the call and add the new struct as friend of your class

          2. In my code, I have a duplication on the /* other dynamic code */ part. You may :

            • Use a function

            • make your template parameter a int instead of size_t and stop at -1 rather than 0


          PS :



          I don't get the part




          in a tuple in a function in a struct (not in a function in the struct)




          I hope I didn't miss something



          Edit :



          My code do one more iteration than your, you may just empty this :



          template < std::size_t MAX, class T>
          struct inner_print_impl<0, MAX , T>
          static void run(const T& caller)


          ;


          And you don't display for the 0 case.






          share|improve this answer















          You should use partial specialization. But you can't do this with a function.



          You should use a struct to do the trick.



          #include <iostream>
          #include <string>
          #include <tuple>

          template <std::size_t N, std::size_t MAX, class T>
          struct inner_print_impl
          static void run(const T& caller)


          std::cout << "Call #"<<MAX-N<< " " << caller.a << std::endl;
          ////////////////////////
          /* other dynamic code */
          ////////////////////////
          inner_print_impl<N-1, MAX , T>::run(caller);

          ;

          template < std::size_t MAX, class T>
          struct inner_print_impl<0, MAX , T>
          static void run(const T& caller)


          std::cout << "Call #"<<MAX<< " " << caller.a << std::endl;
          ////////////////////////
          /* other dynamic code */
          ////////////////////////

          // no recursion

          ;


          template <typename ...Ts>
          struct temp

          using TypeList = std::tuple<Ts...>;
          constexpr static std::size_t N_ = std::tuple_size<TypeList>::value;

          template <std::size_t N, std::size_t MAX, class T>
          friend struct inner_print_impl;
          void print_this()

          inner_print_impl<N_,N_, temp<Ts...> >::run(*this);


          TypeList _mem;

          private :

          int a ; // test acces
          ;

          int main()

          std::string name;
          temp<int, int, int> t1;
          t1.print_this();



          Note :



          1. If you need to acces to a private membre, you will need to pass *this to the call and add the new struct as friend of your class

          2. In my code, I have a duplication on the /* other dynamic code */ part. You may :

            • Use a function

            • make your template parameter a int instead of size_t and stop at -1 rather than 0


          PS :



          I don't get the part




          in a tuple in a function in a struct (not in a function in the struct)




          I hope I didn't miss something



          Edit :



          My code do one more iteration than your, you may just empty this :



          template < std::size_t MAX, class T>
          struct inner_print_impl<0, MAX , T>
          static void run(const T& caller)


          ;


          And you don't display for the 0 case.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jun 5 at 14:47

























          answered Jun 5 at 4:39









          Martin MorterolMartin Morterol

          91428




          91428





















              0














              template<class Integral, Integral N>
              auto dispatch( std::integral_constant<Integral, N> )
              return [](auto&&...args)
              return std::get<N>( std::forward_as_tuple( decltype(args)(args)... ) );
              ;

              template<std::size_t N>
              auto dispatch()
              return dispatch( std::integral_constant<std::size_t, N> );



              this little beauty gives you much of the magic of if constexpr in c++14.



              template <std::size_t N, std::size_t MAX>
              void _inner_print()
              dispatch( std::integral_constant<bool, N==0> )
              (
              // 0, aka false branch:
              [&](auto Nval)
              std::cout << "Call #"<<MAX-Nval<<std::endl;
              ////////////////////////
              /* other dynamic code */
              ////////////////////////
              _inner_print<Nval-1, MAX>();
              ,
              // 1, aka true branch:
              [](auto&&)
              )( std::integral_constant<std::size_t, N> );



              Live example.



              Note that we have to pass in the N via an argument to the lambda, because we want the validity of the lambda's body to vary based on its argument, which is only passed to the right one.




              Alternatively, you can use an overload helper:



              template<class T0, class...Ts>
              struct overloaded;
              template<class Lhs, class Rhs, class...Ts>
              struct overloaded<Lhs, Rhs, Ts...>:
              overloaded<Lhs>, overloaded<Rhs,Ts...>

              using overloaded<Lhs>::operator();
              using overloaded<Rhs,Ts...>::operator();
              template<class A0, class...As>
              explicit overloaded(A0&&a0, As&&...as) :
              overloaded<Lhs>(std::forward<A0>(a0)),
              overloaded<Rhs,Ts...>( std::forward<As>(as)... )

              overloaded(overloaded const&)=default;
              overloaded(overloaded &&)=default;
              overloaded& operator=(overloaded const&)=default;
              overloaded& operator=(overloaded &&)=default;
              ;
              template<class T0>
              struct overloaded<T0> : T0
              using T0::operator();
              template<class A0>
              explicit overloaded(A0&&a0):
              T0(std::forward<A0>(a0))


              overloaded(overloaded const&)=default;
              overloaded(overloaded &&)=default;
              overloaded& operator=(overloaded const&)=default;
              overloaded& operator=(overloaded &&)=default;
              ;
              template<class R, class...Args>
              struct overloaded<R(*)(Args...)>
              R operator()(Args... args) const
              return pf(std::forward<Args>(args)...);

              R(*pf)(Args...);
              overloaded( R(*f)(Args...) ):pf(f)

              overloaded(overloaded const&)=default;
              overloaded(overloaded &&)=default;
              overloaded& operator=(overloaded const&)=default;
              overloaded& operator=(overloaded &&)=default;
              ;
              template<class...Args>
              auto overload( Args&&...args )
              return overloaded<std::decay_t<Args>...>(
              std::forward<Args>(args)...
              );



              Here is how you can use overloaded:



              template <std::size_t N, std::size_t MAX>
              void _inner_print()

              std::integral_constant<std::size_t, N> index;
              overload(
              [](std::integral_constant<std::size_t, 0>) ,
              [&](auto index)
              std::cout << "Call #"<<MAX-index<<std::endl;
              ////////////////////////
              /* other dynamic code */
              ////////////////////////
              _inner_print<index-1, MAX>();

              )(index);



              note that the rule is that the only-sometimes-compiling dynamic code must depend on the auto arguments to the lambda.



              Live example.






              share|improve this answer



























                0














                template<class Integral, Integral N>
                auto dispatch( std::integral_constant<Integral, N> )
                return [](auto&&...args)
                return std::get<N>( std::forward_as_tuple( decltype(args)(args)... ) );
                ;

                template<std::size_t N>
                auto dispatch()
                return dispatch( std::integral_constant<std::size_t, N> );



                this little beauty gives you much of the magic of if constexpr in c++14.



                template <std::size_t N, std::size_t MAX>
                void _inner_print()
                dispatch( std::integral_constant<bool, N==0> )
                (
                // 0, aka false branch:
                [&](auto Nval)
                std::cout << "Call #"<<MAX-Nval<<std::endl;
                ////////////////////////
                /* other dynamic code */
                ////////////////////////
                _inner_print<Nval-1, MAX>();
                ,
                // 1, aka true branch:
                [](auto&&)
                )( std::integral_constant<std::size_t, N> );



                Live example.



                Note that we have to pass in the N via an argument to the lambda, because we want the validity of the lambda's body to vary based on its argument, which is only passed to the right one.




                Alternatively, you can use an overload helper:



                template<class T0, class...Ts>
                struct overloaded;
                template<class Lhs, class Rhs, class...Ts>
                struct overloaded<Lhs, Rhs, Ts...>:
                overloaded<Lhs>, overloaded<Rhs,Ts...>

                using overloaded<Lhs>::operator();
                using overloaded<Rhs,Ts...>::operator();
                template<class A0, class...As>
                explicit overloaded(A0&&a0, As&&...as) :
                overloaded<Lhs>(std::forward<A0>(a0)),
                overloaded<Rhs,Ts...>( std::forward<As>(as)... )

                overloaded(overloaded const&)=default;
                overloaded(overloaded &&)=default;
                overloaded& operator=(overloaded const&)=default;
                overloaded& operator=(overloaded &&)=default;
                ;
                template<class T0>
                struct overloaded<T0> : T0
                using T0::operator();
                template<class A0>
                explicit overloaded(A0&&a0):
                T0(std::forward<A0>(a0))


                overloaded(overloaded const&)=default;
                overloaded(overloaded &&)=default;
                overloaded& operator=(overloaded const&)=default;
                overloaded& operator=(overloaded &&)=default;
                ;
                template<class R, class...Args>
                struct overloaded<R(*)(Args...)>
                R operator()(Args... args) const
                return pf(std::forward<Args>(args)...);

                R(*pf)(Args...);
                overloaded( R(*f)(Args...) ):pf(f)

                overloaded(overloaded const&)=default;
                overloaded(overloaded &&)=default;
                overloaded& operator=(overloaded const&)=default;
                overloaded& operator=(overloaded &&)=default;
                ;
                template<class...Args>
                auto overload( Args&&...args )
                return overloaded<std::decay_t<Args>...>(
                std::forward<Args>(args)...
                );



                Here is how you can use overloaded:



                template <std::size_t N, std::size_t MAX>
                void _inner_print()

                std::integral_constant<std::size_t, N> index;
                overload(
                [](std::integral_constant<std::size_t, 0>) ,
                [&](auto index)
                std::cout << "Call #"<<MAX-index<<std::endl;
                ////////////////////////
                /* other dynamic code */
                ////////////////////////
                _inner_print<index-1, MAX>();

                )(index);



                note that the rule is that the only-sometimes-compiling dynamic code must depend on the auto arguments to the lambda.



                Live example.






                share|improve this answer

























                  0












                  0








                  0







                  template<class Integral, Integral N>
                  auto dispatch( std::integral_constant<Integral, N> )
                  return [](auto&&...args)
                  return std::get<N>( std::forward_as_tuple( decltype(args)(args)... ) );
                  ;

                  template<std::size_t N>
                  auto dispatch()
                  return dispatch( std::integral_constant<std::size_t, N> );



                  this little beauty gives you much of the magic of if constexpr in c++14.



                  template <std::size_t N, std::size_t MAX>
                  void _inner_print()
                  dispatch( std::integral_constant<bool, N==0> )
                  (
                  // 0, aka false branch:
                  [&](auto Nval)
                  std::cout << "Call #"<<MAX-Nval<<std::endl;
                  ////////////////////////
                  /* other dynamic code */
                  ////////////////////////
                  _inner_print<Nval-1, MAX>();
                  ,
                  // 1, aka true branch:
                  [](auto&&)
                  )( std::integral_constant<std::size_t, N> );



                  Live example.



                  Note that we have to pass in the N via an argument to the lambda, because we want the validity of the lambda's body to vary based on its argument, which is only passed to the right one.




                  Alternatively, you can use an overload helper:



                  template<class T0, class...Ts>
                  struct overloaded;
                  template<class Lhs, class Rhs, class...Ts>
                  struct overloaded<Lhs, Rhs, Ts...>:
                  overloaded<Lhs>, overloaded<Rhs,Ts...>

                  using overloaded<Lhs>::operator();
                  using overloaded<Rhs,Ts...>::operator();
                  template<class A0, class...As>
                  explicit overloaded(A0&&a0, As&&...as) :
                  overloaded<Lhs>(std::forward<A0>(a0)),
                  overloaded<Rhs,Ts...>( std::forward<As>(as)... )

                  overloaded(overloaded const&)=default;
                  overloaded(overloaded &&)=default;
                  overloaded& operator=(overloaded const&)=default;
                  overloaded& operator=(overloaded &&)=default;
                  ;
                  template<class T0>
                  struct overloaded<T0> : T0
                  using T0::operator();
                  template<class A0>
                  explicit overloaded(A0&&a0):
                  T0(std::forward<A0>(a0))


                  overloaded(overloaded const&)=default;
                  overloaded(overloaded &&)=default;
                  overloaded& operator=(overloaded const&)=default;
                  overloaded& operator=(overloaded &&)=default;
                  ;
                  template<class R, class...Args>
                  struct overloaded<R(*)(Args...)>
                  R operator()(Args... args) const
                  return pf(std::forward<Args>(args)...);

                  R(*pf)(Args...);
                  overloaded( R(*f)(Args...) ):pf(f)

                  overloaded(overloaded const&)=default;
                  overloaded(overloaded &&)=default;
                  overloaded& operator=(overloaded const&)=default;
                  overloaded& operator=(overloaded &&)=default;
                  ;
                  template<class...Args>
                  auto overload( Args&&...args )
                  return overloaded<std::decay_t<Args>...>(
                  std::forward<Args>(args)...
                  );



                  Here is how you can use overloaded:



                  template <std::size_t N, std::size_t MAX>
                  void _inner_print()

                  std::integral_constant<std::size_t, N> index;
                  overload(
                  [](std::integral_constant<std::size_t, 0>) ,
                  [&](auto index)
                  std::cout << "Call #"<<MAX-index<<std::endl;
                  ////////////////////////
                  /* other dynamic code */
                  ////////////////////////
                  _inner_print<index-1, MAX>();

                  )(index);



                  note that the rule is that the only-sometimes-compiling dynamic code must depend on the auto arguments to the lambda.



                  Live example.






                  share|improve this answer













                  template<class Integral, Integral N>
                  auto dispatch( std::integral_constant<Integral, N> )
                  return [](auto&&...args)
                  return std::get<N>( std::forward_as_tuple( decltype(args)(args)... ) );
                  ;

                  template<std::size_t N>
                  auto dispatch()
                  return dispatch( std::integral_constant<std::size_t, N> );



                  this little beauty gives you much of the magic of if constexpr in c++14.



                  template <std::size_t N, std::size_t MAX>
                  void _inner_print()
                  dispatch( std::integral_constant<bool, N==0> )
                  (
                  // 0, aka false branch:
                  [&](auto Nval)
                  std::cout << "Call #"<<MAX-Nval<<std::endl;
                  ////////////////////////
                  /* other dynamic code */
                  ////////////////////////
                  _inner_print<Nval-1, MAX>();
                  ,
                  // 1, aka true branch:
                  [](auto&&)
                  )( std::integral_constant<std::size_t, N> );



                  Live example.



                  Note that we have to pass in the N via an argument to the lambda, because we want the validity of the lambda's body to vary based on its argument, which is only passed to the right one.




                  Alternatively, you can use an overload helper:



                  template<class T0, class...Ts>
                  struct overloaded;
                  template<class Lhs, class Rhs, class...Ts>
                  struct overloaded<Lhs, Rhs, Ts...>:
                  overloaded<Lhs>, overloaded<Rhs,Ts...>

                  using overloaded<Lhs>::operator();
                  using overloaded<Rhs,Ts...>::operator();
                  template<class A0, class...As>
                  explicit overloaded(A0&&a0, As&&...as) :
                  overloaded<Lhs>(std::forward<A0>(a0)),
                  overloaded<Rhs,Ts...>( std::forward<As>(as)... )

                  overloaded(overloaded const&)=default;
                  overloaded(overloaded &&)=default;
                  overloaded& operator=(overloaded const&)=default;
                  overloaded& operator=(overloaded &&)=default;
                  ;
                  template<class T0>
                  struct overloaded<T0> : T0
                  using T0::operator();
                  template<class A0>
                  explicit overloaded(A0&&a0):
                  T0(std::forward<A0>(a0))


                  overloaded(overloaded const&)=default;
                  overloaded(overloaded &&)=default;
                  overloaded& operator=(overloaded const&)=default;
                  overloaded& operator=(overloaded &&)=default;
                  ;
                  template<class R, class...Args>
                  struct overloaded<R(*)(Args...)>
                  R operator()(Args... args) const
                  return pf(std::forward<Args>(args)...);

                  R(*pf)(Args...);
                  overloaded( R(*f)(Args...) ):pf(f)

                  overloaded(overloaded const&)=default;
                  overloaded(overloaded &&)=default;
                  overloaded& operator=(overloaded const&)=default;
                  overloaded& operator=(overloaded &&)=default;
                  ;
                  template<class...Args>
                  auto overload( Args&&...args )
                  return overloaded<std::decay_t<Args>...>(
                  std::forward<Args>(args)...
                  );



                  Here is how you can use overloaded:



                  template <std::size_t N, std::size_t MAX>
                  void _inner_print()

                  std::integral_constant<std::size_t, N> index;
                  overload(
                  [](std::integral_constant<std::size_t, 0>) ,
                  [&](auto index)
                  std::cout << "Call #"<<MAX-index<<std::endl;
                  ////////////////////////
                  /* other dynamic code */
                  ////////////////////////
                  _inner_print<index-1, MAX>();

                  )(index);



                  note that the rule is that the only-sometimes-compiling dynamic code must depend on the auto arguments to the lambda.



                  Live example.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Jun 5 at 14:25









                  Yakk - Adam NevraumontYakk - Adam Nevraumont

                  193k21210399




                  193k21210399



























                      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%2f56454091%2fif-constexpr-with-recursive-parameter-packs%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

                      How to write a 12-bar blues melodyI-IV-V blues progressionHow to play the bridges in a standard blues progressionHow does Gdim7 fit in C# minor?question on a certain chord progressionMusicology of Melody12 bar blues, spread rhythm: alternative to 6th chord to avoid finger stretchChord progressions/ Root key/ MelodiesHow to put chords (POP-EDM) under a given lead vocal melody (starting from a good knowledge in music theory)Are there “rules” for improvising with the minor pentatonic scale over 12-bar shuffle?Confusion about blues scale and chords

                      What if the end-user didn't have the required library?What is setup.py?What is a clean, pythonic way to have multiple constructors in Python?What does Ruby have that Python doesn't, and vice versa?What is the reason for having '//' in Python?How do I create a namespace package in Python?How to package shared objects that python modules depend on?setuptools vs. distutils: why is distutils still a thing?Navigation in Windows 10 vs code not going to virtualenv library when the same library is installed at user levelPython create package for local usePackaging a project that uses multiple python versionsWhy is permission denied on pip install except for when “--user” is included at end of command?

                      Why did Thanos need his ship to help him in the battle scene?Which actor plays Thanos in the Avengers mid-credits scene?Are there economic implications portrayed in comics where the buildings and cities are ruined almost daily?Old X-Men comic where team travels to alien world with a ring-like sun that needs recharging?Why does Ego need help sleeping?Is there an objective answer to who “the strongest Avenger” is?How did Banner get unstuck?Why did Thanos get hit?How did Thanos (or anyone) know the Infinity Stones would give him this power?Did Thanos leave Eitri alive for his after-sales service?In Avengers 1, why does Thanos need Loki?