Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forwarding template taking precedence over overload

I thought that a non-template would always take precedence over a template, if the arguments match up just as well.

But:

template <typename... Args>
void Trace(Args&&... args)
{
    throw "what the frak";
}

void Trace(const int&)
{}

int main()
{
    Trace(42);
}

This throws unless I make the non-template Trace(int) or Trace(int&&), i.e. not taking a const ref.

It's kind of annoying because I want to provide a different implementation for specific argument types where the real implementation of the template does not make sense (and, in fact, would not compile).

I can fix it by making the second function a specialisation, but only if I match argument types by taking an rvalue reference:

template <>
void Trace(int&&)
{}

And, well, maybe I didn't want to do that! Maybe I want to call it with a const thing sometimes and would rather not specialise twice.

Is it correct and standard-abiding that simply providing a non-template overload works this way, in this example? It's the first time I've noticed this behaviour (not that that necessarily means anything!).

like image 384
Lightness Races in Orbit Avatar asked Sep 11 '19 11:09

Lightness Races in Orbit


1 Answers

42 is an rvalue of type int, therefore it binds more closely to int&& rather than const int&. This is why it is calling your template Trace function.

If you were to call

const int i{};
Trace(i);

then your Trace(const int&) overload would be invoked.


Possible workarounds:

  • Add a Trace(int&&) overload that invokes Trace(const int&). You might also need a Trace(int&);

  • Use SFINAE on the templated Trace to prevent instantiation when the first argument is an int;

    template <typename Arg, typename... Args>
    auto Trace(Arg&& arg, Args&&... args)
        -> std::enable_if_t<!std::is_same_v<std::decay_t<Arg>, int>>
    {
        throw "what the frak";
    }   
    
  • Change the templated Trace to take const Args&... instead.

like image 195
Vittorio Romeo Avatar answered Sep 28 '22 00:09

Vittorio Romeo