Question

I have a one method interface and a class mocking that interface. The method takes a single argument. Only when that argument is of type std::pair<Something, Something> does it fail to compile. I'm working with MSVC 2010, so it is possible the issue is compiler or STL implementation specific, unless, of course, the problem is wetware related, which is my best guess. I must be missing something obvious. Like nanoprobes.

#include <gmock/gmock.h>

class BorgInterface
{
public:
    typedef std::pair<int, long> MyBorg; // <--- MyBorg is problematic!
    //typedef long MyBorg; // ..but this MyBorg complies
    virtual void Assimilate( MyBorg borg_in_training ) = 0;
};

class MockBorg
    : public BorgInterface
{
public:
    MOCK_METHOD1( Assimilate, void( BorgInterface::MyBorg borg_in_training ));
};

/*TEST( MyBorgTestCase, BorgInterfaceTest )
{
    using ::testing::_;

    MockBorg funny_borg;
    EXPECT_CALL( funny_borg, Assimilate( _ ));
    // ...etc. (irrelevant)
}*/

The actual test case does not have to be uncommented for the error to manifest itself.

For now, I work around this issue by wrapping the std::pair<> in a struct, but this is sub-optimal.

The length of the error message is rather unfortunate, but it may help:

1>Build started 3/31/2012 4:02:43 PM.
1>ClCompile:
1>  test_pair_parameter_mock.cpp
1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\tuple(127):
   error C2664: 'std::pair<_Ty1,_Ty2>::pair(const std::pair<_Ty1,_Ty2> &)'
       : cannot convert parameter 1 from 'int' to 'const std::pair<_Ty1,_Ty2> &'
1>          with
1>          [
1>              _Ty1=int,
1>              _Ty2=long
1>          ]
1>          Reason: cannot convert from 'int' to 'const std::pair<_Ty1,_Ty2>'
1>          with
1>          [
1>              _Ty1=int,
1>              _Ty2=long
1>          ]
1>          No constructor could take the source type,
             or constructor overload resolution was ambiguous
1>          c:\...\microsoft visual studio 10.0\vc\include\tuple(404)
               : see reference to function template instantiation
                'std::tr1::_Cons_node<_Car,_Cdr>::_Cons_node<
                  _Ty1&,_Ty2&,std::tr1::_Nil&,std::tr1::_Nil&,
                  std::tr1::_Nil&,
                  ...............
                  std::tr1::_Nil&,
                  std::tr1::_Nil&>(_Farg0,...,_Farg9)' being compiled
1>          with
1>          [
1>              _Car=BorgInterface::MyBorg,
1>              _Cdr=std::tr1::_Tuple_type<
                  std::tr1::_Nil,
                  ..............
                  std::tr1::_Nil,
                  std::tr1::_Nil>::_Type,
1>              _Ty1=int,
1>              _Ty2=long,
1>              _Farg0=int &,
1>              _Farg1=long &,
1>              _Farg2=std::tr1::_Nil &,
1>              .......................
1>              _Farg9=std::tr1::_Nil &
1>          ]
1>          d:\...\gmock\include\gmock\gmock-generated-function-mockers.h(97) :
                see reference to function template instantiation
                 'std::tr1::tuple<_Arg0>::tuple<int,long>(
                   std::pair<_Ty1,_Ty2> &)' being compiled
1>          with
1>          [
1>              _Arg0=BorgInterface::MyBorg,
1>              _Ty1=int,
1>              _Ty2=long
1>          ]
1>          d:\...\gmock\include\gmock\gmock-generated-function-mockers.h(92) :
               while compiling class template member function
                'void testing::internal::FunctionMocker<Function>::Invoke(A1)'
1>          with
1>          [
1>              Function=void (BorgInterface::MyBorg),
1>              A1=BorgInterface::MyBorg
1>          ]
1>          d:\..\myapp\src\tests\unit_tests\test_pair_parameter_mock.cpp(17) :
               see reference to class template instantiation
                'testing::internal::FunctionMocker<Function>' being compiled
1>          with
1>          [
1>              Function=void (BorgInterface::MyBorg)
1>          ]
1>
1>Build FAILED.
Was it helpful?

Solution

Looks like a compiler issue indeed; this compiles OK using gcc 4.6.

A simpler workaround would be to pass MyBorg by pointer to const:

    virtual void Assimilate( const MyBorg *borg_in_training ) = 0;

or if you are happy to use Boost, you could replace std::pair with boost::tuple

    typedef boost::tuple<int, long> MyBorg;

OTHER TIPS

If you want a full explanation of the issue, there is a bug report on this issue with a detailed discussion and investigation. It's specific to VS2010 because of a tuple constructor that takes a pair directly. The relevant note is

trying to construct a tuple< pair < T0, T1 > > from a pair< T0, T1 > results in a call to the first constructor mentioned above which in turn tries to assign T0 to pair< T0, T1 >, yielding the error.

The solution would be to enable the tuple from pair constructor only if T0 and T1 from the pair< T0, T1 > given as argument match T0 and T1 from the tuple< T0, T1 > being constructed.

It's a defect in VS2010's STL implementation and has been fixed in VS2012's STL implementation.

I successfully worked around the issue by adding a default parameter to the function signature to avoid having a single pair< T0, T1 > parameter. That results in the problematic constructor being avoided.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top