0

Why is "TArgs" ambiguous in my Example?

The compiler should know the only existing function signature

virtual CGame::NetCreatePlayer(CNetPeer* _pPeer, int _ObjectID, const CNetMessage& _ObjectData, bool _bAuthority); 

and deduce correct TArgs in this function:

template<typename... TArgs >
void INetInterface<TSubClass>::NetCall(void(TSubClass::*_pFunc)(CNetPeer*, TArgs...), CNetPeer* _pPeer, TArgs... _Params);

I want to call it like this:

CNetMessage obj;
//...
NetCall(&CGame_Server::NetCreatePlayer, _pClient, 0, obj, true);

CGame_Server inherits CGame.

Compiler output:

4> error C2782: 'void INetInterface<CGame>::NetCall(void (__thiscall CGame::* )(CNetPeer *,TArgs...),CNetPeer *,TArgs...)' : template parameter 'TArgs' is ambiguous 4> NetInterface.h(82) : see declaration of INetInterface<CGame>::NetCall' 4> could be 'int, const CNetMessage&, bool' 4> or 'int, CNetMessage, bool'

It can't be 'int, CNetMessage, bool', right?

Is there a way to get around this problem? I tried casting to const CNetMessage& but strangely enough that does not help. And no there are no other member functions with that same name.

T.C.
  • 133,968
  • 17
  • 288
  • 421
ecreif
  • 1,182
  • 1
  • 12
  • 25

1 Answers1

2
NetCall(&CGame_Server::NetCreatePlayer, _pClient, 0, obj, true);

There are two places in this call from which TArgs can be deduced:

  • From the member function pointer's type, the compiler deduces TArgs == int, const CNetMessage&, bool
  • From the parameters 0, obj, true, the compiler deduces TArgs == int, CNetMessage, bool

The results conflict. To fix this, use the identity trick to put the second TArgs into a non-deduced context:

template<class T> struct identity { using type = T; };    
template<class T> using identity_t = typename identity<T>::type;

template<typename... TArgs >
void INetInterface<TSubClass>::NetCall(void(TSubClass::*_pFunc)(CNetPeer*, TArgs...),
                                       CNetPeer* _pPeer, identity_t<TArgs>... params);

As a side note, _Params is a reserved identifier, along with _ObjectData and _ObjectID; you should rename them.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Thanks for the nice hints, I will try it out later. Seems like I have to change my coding style as I am using "_" for parameters. I have not thought about that I can collide with reserved identifiers this way. – ecreif Feb 18 '15 at 07:30
  • I still dont understand why this is a conflict? The compiler could find the non error solution without violating type safety due to the function pointer being resolved first and "fixing" the possible TArgs parameter to one solution. Now when it sees the second use of TArgs it should continue using const CMessage& for it from the function signature first deduced. Applying that would not result in error. So is this not working by definition? – ecreif Feb 18 '15 at 07:39
  • 1
    @ecreif Because the rule is that when it's used several times, then it's deduced independently and all deductions must match. Presumably one motivation for the rule is to avoid introducing unexpected conversions in ambiguous cases. – T.C. Feb 18 '15 at 07:57