Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
297 views
in Technique[技术] by (71.8m points)

c++ - 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!).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...