Home > Net >  Why is there a difference between templated recursive calls and fold expressions with type cast or p
Why is there a difference between templated recursive calls and fold expressions with type cast or p

Time:11-01

#include <array>
#include <type_traits>
#include <iostream>

template<class... Types>
class Test {
 public:
  Test()
    : format_({
      [&] {
      if constexpr(std::is_same_v<Types, int64_t>) {
        return "%ld ";
      } else if constexpr(std::is_same_v<Types, int32_t>) {
        return "%d ";
      } else if constexpr(std::is_same_v<Types, double>) {
        return "%f ";
      }
      }() ...
    }) {}

  template<typename T, typename ... Args>
  void print_recursive(T && v, Args && ... args) {
    size_t i = sizeof...(Types) - sizeof...(args) - 1;
    printf(format_[i], std::forward<T>(v));
    if constexpr(sizeof...(Args) > 0) {
      print_recursive(std::forward<Args>(args)...);
    } else {
      printf("\n");
    }
  }

  void print_fold(Types && ... args) {
    size_t i = 0;
    ([&]{
      printf(format_[i  ], args);
    }(), ...);
    printf("\n");
  }

 private:
  std::array<const char*, sizeof...(Types)> format_;
};

int main() {
  Test<int64_t, int32_t, double> t;
  t.print_recursive(1.0, 2, 3.0);
  t.print_fold(1.0, 2, 3.0);
}

OUTPUT:

0 2 3.000000 
1 2 3.000000 

Built and ran with the following:

g   test.cpp -o test -std=c  17 && ./test

Compiler Info:

$ gcc --version
gcc (GCC) 9.2.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

In the above example, the format_ array is defined using fold expressions and used in both print calls. Each print call has the same format specifier for the same index. Each print call has the same args past to it as well. However the output is different for the two. Why is that the case?

EDIT: Adding the correct recursive call that will convert the function arguments to the class template types first before making the recursive call as recommended by @n. m.

  void print_recursive(Types && ... args) {
    print_recursive_impl(std::forward<Types>(args)...);
  }

  template<typename T, typename ... Args>
  void print_recursive_impl(T && v, Args && ... args) {
    size_t i = sizeof...(Types) - sizeof...(args) - 1;
    printf(format_[i], std::forward<T>(v));
    if constexpr(sizeof...(Args) > 0) {
      print_recursive_impl(std::forward<Args>(args)...);
    } else {
      printf("\n");
    }
  }

CodePudding user response:

You print double as an integer in the recursive call. That's a UB or some other nonsense.

In the fold version you convert them to the appropriate types first.

  • Related