Home > Back-end >  Overloaded method resolution for variadic tuples displays strange results
Overloaded method resolution for variadic tuples displays strange results

Time:07-27

I'm getting strange and unexpected results for this code: https://godbolt.org/z/8vs87vcKK

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

using namespace std;

struct Foo
{
  template < typename ... t_Tys >
  static void foo( tuple< t_Tys ... > const & )
  {
    cerr << "foo()\n";
  }
  template < class ... t_Tys >
  static void foo( tuple< string, t_Tys ... > const & _rtp )
  {
    cout << "foo( string )\n";
  }
  template < class ... t_Tys >
  static void foo( tuple< string, int, t_Tys ... > const & _rtp )
  {
    cout << "foo( string, int ) [" << get<1>(_rtp) << "]\n";
  }
};
int main()
{
  Foo::foo( make_tuple<string>( "foo" ) );
  Foo::foo( make_tuple<int>( 1 ) );
  Foo::foo( make_tuple( "foo", 1 ) );
  Foo::foo( make_tuple<string,int>( "foo", 1 ) );
}

Output is:

foo()
foo()
foo( string )
foo( string, int ) [1]

First question: I would expect that the first "foo()" would be "foo( string )", why is this not the case?

Then when I change the first call to foo() to this:

Foo::foo( make_tuple( "foo" ) );

https://godbolt.org/z/zh9G39z61

the output is:

foo()
foo()
foo()
foo( string, int ) [1]

Question 2: Why did the change to the first call to foo() not generate a call to foo( tuple< string> const & )?

Question 3: Why did the change to the first call to foo() cause the overload chosen by the third call to foo() to change? This one is really weird to me as it indicates a side effect of the first call and that just doesn't make sense to me.

Thanks in advance.

CodePudding user response:

The first template is using cerr, while the others are using cout. Since you used '\n' instead of endl to end the line, your output is not immediately flushed. This is reordering your output. Fixing this, the first output becomes:

foo( string )
foo()
foo()
foo( string, int ) [1]

The first foo() does indeed result in foo( string ), while the third foo() was actually foo(). The change to the first call to foo() did not cause any side effects to the third call.

As for why foo( make_tuple( "foo" ) ) doesn't use the string template, that's because when you pass in a string constant to make_tuple, it returns a tuple<char const * const>.

  • Related