3

I ran into errors while partially specializing a template with boost::tuple. The same code compiled on replacing boost::tuple with std::tuple. Here's the code condensed into the part that fails to compile.

template <typename... Args>
class Test;

template <typename... Args>
class Test<std::tuple<Args...>, Args...>
{
};

template <typename... Args>
class Test<boost::tuple<Args...>, Args...>
{
};

int main()
{
  int rc;

  cout<<abi::__cxa_demangle(typeid(Test<boost::tuple<int, int>, int,int>).name(), 0, 0, &rc)<<endl;//Doesn't compile                                                           
  cout<<abi::__cxa_demangle(typeid(Test<std::tuple<int, int>, int,int>).name(), 0, 0, &rc)<<endl;//Compiles
  return 0;
}

The compile error, with g++48, is

tuplerr.cpp: In function ‘int main()’:
tuplerr.cpp:30:73: error: invalid use of incomplete type ‘class Test<boost::tuples::tuple<int, int, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>, int, int>’
cout<<abi::__cxa_demangle(typeid(Test<boost::tuple<int, int>, int,int>).name(), 0, 0, &rc)<<endl;//Doesn't compile
                                                                     ^
tuplerr.cpp:14:7: error: declaration of ‘class Test<boost::tuples::tuple<int, int, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>, int, int>’
class Test;

However, the specialization using std::tuple works just fine. What am I doing wrong?

Pradhan
  • 16,391
  • 3
  • 44
  • 59

2 Answers2

5

Try this

// used below to create a "non-deduced context"
template<typename T>
struct Id { typedef T type; };

template <typename... Args>
class Test;

template <typename... Args>
class Test<typename Id<std::tuple<Args...>>::type, Args...>
{
};

template <typename... Args>
class Test<typename Id<boost::tuple<Args...>>::type, Args...>
{
};

So that the optional parameters in boost::tuple (which have default arguments because your boost's tuple implementation uses that to simulate variadic templates) don't make the first Args... contradict with the later Args... expansion that only has the required explicitly passed arguments.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Why does a similar specialization work when using a fixed number of arguments? For example, if `Test` was taking two template arguments and I tried to do a similar partial specialization to ensure the first argument is a `boost::tuple` wrapping around the second argument, the code compiles. – Pradhan Feb 27 '14 at 22:47
  • Also, the modified version fails as well with the icc14. Guess they still have a few kinks to iron out. – Pradhan Feb 28 '14 at 01:28
1

boost::tuple doesn't work with variadic templates.

See here https://stackoverflow.com/a/2709502/2524462 for a workaround.

Community
  • 1
  • 1
Mike M
  • 2,263
  • 3
  • 17
  • 31
  • Can you elaborate on the first claim? – sehe Feb 27 '14 at 21:43
  • Nope, but I had the chance to learn from Johannes' answer. That said ``int, int, int, int, int, int, int, int, int, int`` works with the initial code. – Mike M Feb 27 '14 at 21:56
  • Interesting observation indeed. – sehe Feb 27 '14 at 21:56
  • 1
    Well from his answer, it needs to work since boost emulates variadic templates with 10 (if no other value is set by the user). 9xint fails as expected. – Mike M Feb 27 '14 at 21:59