3

I am trying out the code from http://florianjw.de/en/variadic_templates.html:

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

template<typename Fun, typename...Ts>
void sequential_foreach(Fun f, const Ts&... args) {
  (void) std::initializer_list<int>{
    [&](const auto& arg){f(arg); return 0;}(args)...
  };
}

template<typename...Ts>
void print_all(std::ostream& stream, const Ts&... args) {
  sequential_foreach([&](const auto& arg){stream << arg;}, args...);
}

int main()
{
  std::string s1("string1");
  std::string s2("string2");
  print_all(std::cout, s1, s2);

  return 0;
}

But I am getting the following errors: (when I pass more than one parameter to print_all)

main.cpp: In instantiation of ‘void sequential_foreach(Fun, const Ts& ...) [with Fun = print_all(std::ostream&, const Ts& ...) [with Ts = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; std::ostream = std::basic_ostream<char>]::<lambda(const auto:2&)>; Ts = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]’:
main.cpp:14:67:   required from ‘void print_all(std::ostream&, const Ts& ...) [with Ts = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; std::ostream = std::basic_ostream<char>]’
main.cpp:21:30:   required from here
main.cpp:8:5: error: uninitialized const member ‘sequential_foreach(Fun, const Ts& ...) [with Fun = print_all(std::ostream&, const Ts& ...) [with Ts = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}; std::ostream = std::basic_ostream<char>]::<lambda(const auto:2&)>; Ts = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}]::<lambda(const auto:1&)>::<f capture>’
     [&](const auto& arg){f(arg); return 0;}(args)...
     ^

What am I doing wrong? ideone link: https://ideone.com/

I tried with ideone (gcc5.1 c++14) and on Redhat 6 gcc version 4.9.1 20140922 (Red Hat 4.9.1-10)

Patryk
  • 22,602
  • 44
  • 128
  • 244
  • 1
    It compiles fine in Visual Studio and latest Clang apparently. Did you intentionally not include ? http://coliru.stacked-crooked.com/a/aafca0fdb174287f – DeiDei Oct 31 '15 at 17:52
  • 1
    @DeiDei Ok my bad with `#include ` but still it doesn't compile neither on my machine nor on ideone. – Patryk Oct 31 '15 at 17:55
  • One thing I can notice is that the lambda is `print_all` should be made `mutable` (as by default the lambda are const which makes the captured stream const as well, which should not work; *I dont know if references has different rules*). Other than that, I dont see any issue. However, you've made your code unnecessarily complex. See how I've [simplified it](https://ideone.com/eIejtW). – Nawaz Oct 31 '15 at 18:03
  • 3
    @Nawaz No, `mutable` is not necessary as we're capturing a reference by reference. See §5.1.2/15. – Columbo Oct 31 '15 at 18:06
  • 1
    The key part of the error is `error: uninitialized const member ‘...::::’`, but as to _why_.... all I can guess is a GCC bug. Interestingly coliru's gcc says `error: member '...::::' is uninitialized reference`. – Mooing Duck Oct 31 '15 at 18:09
  • Rewriting as `auto fun = [&](const auto& arg){f(arg); return 0;}; (void) std::initializer_list{ fun(args)... };` makes it compile in GCC. GCC's handling of lambdas in pack expansions is known to be buggy; this might be another manifestation. – T.C. Nov 01 '15 at 09:20
  • @T.C. This worked :) [ideone.com/ywVhFm](http://ideone.com/ywVhFm) You can post this as answer T.C. So that would mean that we cannot initilize `std::initializer_list` with lambda in variadic templates in gcc (up to 5.1)? – Patryk Nov 01 '15 at 10:29

1 Answers1

1

As T.C. hasn't posted this as an answer I am posting it here so that everyone can find it.

ideone link

#include <tuple>
#include <initializer_list>
#include <iostream>
#include <string>
#include <vector>

template<typename Fun, typename...Ts>
void sequential_foreach(Fun f, const Ts&... args) {
  auto fun = [&](const auto& arg){f(arg); return 0;};
  (void) std::initializer_list<int>{ fun(args)... };
}

template<typename...Ts>
void print_all(std::ostream& stream, const Ts&... args) {
  sequential_foreach(
      [&](const auto& arg){stream << arg;},
      args...
      );
}

int main()
{
  std::string s1("string1");
  std::string s2("string2");
  print_all(std::cout, s1, s2);

  return 0;
}
Patryk
  • 22,602
  • 44
  • 128
  • 244