3

There was a discussion about function specialization here: Will specialization of function templates in std for program-defined types no longer be allowed in C++20?

In principal I understand, that it is better to overload instead of specialize. But how do you overload a std function template properly? The canonical answer seems to be: just overload in your custom namespace and then ADL kicks in. But this doesn't work, if fundamental types are involved. Non-working example:

#include <cmath>

namespace X {

class Y {    };

Y sqrt(Y); 

double foo(double x) { return sqrt(x); }

}

The example will only compile without the sqrt declaration for Y. One can solve the issue by overloading in namespace std instead:

#include <cmath>

namespace X {
    class Y {    };
}

namespace std { X::Y sqrt(X::Y); }

namespace X {

double foo(double x) 
{
  return sqrt(x);
}

}

This code does exactly what I want to do. However I am unsure, if this kind of overloading is permitted by the standard. At cppreference I don't find a hint toward this direction. And while this paper of Walter E. Brown proposes overloading as an alternative to specialization, I am unsure, if the above example uses it right (the paper doesn't give any examples).

6
  • What's wrong with calling std::sqrt(x); or using std::sqrt inside foo? Commented May 31, 2021 at 11:24
  • Regarding std::sqrt(x); see below. And writing using std::sqrt (same for sin, exp aso.) all over the places in your code just to reactivate standard functions for fundamental types feels rather like a language flaw. Commented May 31, 2021 at 12:16
  • 1
    #include <cmath> does not have to bring sqrt et al into global namespace. Your implementation does that for one reason or another, but that's not what the language guarantees. Normally you should be calling std::sqrt everywhere, or saying using std::sqrt, regardless of whether you define your own sqrt. Commented May 31, 2021 at 12:26
  • Regarding "see below", I came from below hoping to get a hint here what the problem actually is. You seem the be expecting std::sqrt to be something that it isnt. You want something else so you need to do a tiny bit extra. Its not a language flaw, i'd rather consider it as a langauge flaw if std::sqrt could call whatever, but is not guaranteed to be std::sqrt. Commented May 31, 2021 at 12:28
  • You might be interested by P1292R0 Customization Point Functions. Commented May 31, 2021 at 13:26

2 Answers 2

2

Adding overloads of sqrt to the std namespace is not permitted.

You can however either use the fully qualified name, or give std::sqrt preference by adding using std::sqrt:

#include <cmath>

namespace X {

class Y {    };

Y sqrt(Y) { return {}; } 

double foo(double x) { 
    return std::sqrt(x); 
}

} // namespace X

template <typename T>
T bar(T x){
    using std::sqrt;
    return sqrt(x);
}

double baz(double x){
    using std::sqrt;
    return sqrt(x);
}

double moo(double x){
    return bar(x);
}

X::Y zoo(X::Y x){
    return bar(x);
}

Note that std::sqrt disables ADL, while using std::sqrt still allows ADL to kick in, as exemplified by bar which is called from moo and zoo.

Sign up to request clarification or add additional context in comments.

5 Comments

This was exactly the answer I was afraid of. As you've noted, full qualification doesn't work with templates. And writing using std::sqrt becomes painful in numerical codes. And all theses problems only, because fundamental data types don't add std to their ADL namespaces. BTW, a while ago I asked a related question: stackoverflow.com/questions/64785956
@krzikalla "As you've noted, full qualification doesn't work with templates. " sry I dont understand what you mean by that.
Sorry, the commenting UI is difficult to master. Anyway, thanks for the answer. It looks like I have to use using std::sqrt; in theory. In practice I have to violate the std.
@krzikalla I am a bit lost on why you see a problem.
@krzikalla if "writing using std::sqrt [...] all over the place" is what worries you then you can write a wrapper my_sqrt that can be called without such quirks.
0

Answering my own question (but wouldn't have found it without the discussion here):

#include <cmath>

namespace X {
namespace details {

class Y {    };

Y sqrt(Y); 

} // ns details

using details::Y;

double foo(double x) { return sqrt(x); }

} // ns X

Now foo can remain as it is and sqrt(Y) is possible.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.