Should operators be declared as non-member non-template friends - c++

Consider this question, which is about the following code not compiling:
std::vector<int> a, b;
std::cout << (std::ref(a) < std::ref(b));
It doesn't compile because the vector comparison operators for vector are non-member function templates, and implicit conversions aren't allowed to be considered. However, if the operators were instead written as non-member non-template, friend functions:
template <class T, class Allocator = std::allocator<T>>
class vector {
// ...
friend bool operator<(const vector& lhs, const vector& rhs) {
// impl details
}
};
Then this version of operator< would have been found by ADL and been chosen as the best viable overload, and the original example would have compiled. Given that, is there a reason to prefer the non-member function template that we currently have, or should this be considered a defect in the standard?

Given that, is there a reason to prefer the non-member function
template that we currently have, or should this be considered a defect
in the standard?
The reason is if ADL could find out proper function or not. When such a search requires to extract the substituted template parameters from the type of given object and then substitute them many times into a templated parameter of the function template, ADL can't do this because of there are no reasons in the general case to prefer one way of template parameters binding to other. The non-member function template defined after but still in the namespace scope of that template (due to friend) excludes such an indeterminacy.

Related

Compiler throws "ambiguous overload for operator"

I'm learning how to use std::chrono and I want to make a template class Timer easy to use (defined in timer.h). The testing program was successful and everything worked fine, until I tried to use my new Timer in a program with the definition of some template operators, which conflit with the operators used inside Timer.
Inside Timer I have to use operator- between two variables (start_time and end_time) of type std::chrono::time_point, in order to obtain the duration variable containing the elapsed time.
In another header (algebra.h) I implemented the overloading of the binary operator- to make the difference between two std::vector or two std::array, or also a user-defined container provided with operator[] and size() member function.
template<typename pointType>
pointType operator-(pointType a, const pointType & b){
for(int i = 0; i < a.size(); ++i){
a[i] = a[i] - b[i];
}
return a;
}
When I try to include both timer.h and algebra.h, the compiler throws an error saying "ambiguous overload for operator-" suggesting, as possible candidates, both the operator in algebra.h and the one implemented in <chrono>.
I don't understand why it is ambiguous, since pointType can't be deduced as std::chrono::time_point because it doesn't have operator[] and size() member function.
P.S. I tried something else to work it out, but I only got more confused testing a program which use std::valarray. When I include both <valarray> and "algebra.h", and try to make a difference between two valarrays, I expected the compiler to complain about ambiguous definition of operator-, since std::valarray already has implementation for binary operators. But this doesn't happen: it compiles using the <valarray> implementation. Why this doesn't throw an error?
It is ambiguous because the compiler only looks at the function signature to test for ambiguity, not the body of the function. In your example, this is the function signature:
template<typename pointType>
pointType operator-(pointType a, const pointType & b)
Here, the template parameter pointType could be deduced as std::chrono::time_point. However, there is already a binary minus operator declared in the chrono header for std::chrono::time_point (https://en.cppreference.com/w/cpp/chrono/time_point/operator_arith2). This is what is causing the ambiguity error.
To solve this problem, you should first consider whether you need such a generic binary minus operator. The problem you are currently experiencing will not be unique to std::chrono::time_point, but will also occur with any other header that contains a class with a member or non-member binary minus operator, where both arguments are of the same type (or could implicitly convert into the same type). Perhaps a simple set of function overloads for the types in question:
template<typename T>
std::vector<T> operator-(const std::vector<T>& a, const std::vector<T>& b);
template<typename T, size_t N>
std::array<T,N> operator-(const std::array<T,N>& a, const std::array<T,N>& b);
This would be the safest option. You could also not use operator overloading altogether, and stick to a conventional function:
template<typename T>
T pointwise_subtract(const T& a, const T& b);
If you have a c++20 compiler, you could use concepts. If you insist on using non-member operator templates, you may have to use SFINAE-based template metaprogramming, a more advanced and less readable technique:
//enable this template if the type T has a member method "size" and
// subscript operator accepting variables of type "size_t"
template<typename T, typename=std::void_t<
decltype(std::declval<T>().size()),
decltype(std::declval<T>()[std::declval<size_t>()])
>
T operator-(const T& a, const T& b);
This will remove your ambiguity error.

How does one declare an out of class binary operator for a templated class? [duplicate]

This question already has answers here:
What are the basic rules and idioms for operator overloading?
(8 answers)
Closed 4 years ago.
I have a situation where I have math operations that make sense to overload for convenience.
But some of them operate on other types.
Like
vec3<type> * type
and
type * vec3<type>
One way for the right hand argument for a scalar is:
template<class T, class SubT>
class Vec3 {
// this is fine, ie: works
SubT operator *(const T &val) {
return(SubT(x*val,y*val,z*val));
}
};
Ive read that is is best only to implement operators for *, +, -, /, etc "out of class" or let the compiler deduce things from the += version in the class.
is this optimal vs having + implemented in the class?
how does one do this for the reverse where the left hand argument is the other type?
Ie in my particular case, the templated operator has two template type arguments. One is the type of the element, and the other is the super class the template is implementing it's methods for.
template<class T, class SubT>
SubT operator *(const T &a, const Vec3Base<T, B> &b) {
return(b * a);
}
Anyway hopefully you get my desire, how to do it properly is the question :)
Like do I need to only make to take one type ? ie: the vector type, and then get the element type from it as a typedef ??
template<class VT>
VT::SubT operator*(const VT::ElemT &a, const VT &v) {
return(v * a);
}
and should I also implement the other way instead of in the class but "out of class" with:
template<class VT>
VT::SubT operator*(const VT &a, const VT::ElemT &b ) {
return(VT::SubT(a.x*b,a.y*b,a.z*b));
}
Well I did read most of the answers in the idioims for operator overloading question.
I does answer a lot of things. BUT doesn't cover the ramafacations for templates and templates declaring operators used in the subclasses of those templates.
For all operators where you have to choose to either implement them as a member function or a non-member function, use the following rules of thumb to decide:
This was somewhat helpful in my desire to know the best way to implement whether out of class or in the class.
If it is a unary operator, implement it as a member function.
If a binary operator treats both operands equally (it leaves them unchanged), implement this operator as a non-member function.
If a binary operator does not treat both of its operands equally (usually it will change its left operand), it might be useful to make
it a member function of its left operand’s type, if it has to access
the operand's private parts.
I was wondering if there is an issue regarding prioritization of one over the other for templates. I find if an operator is declared in a template and it is a superclass of a subclass that inherits it's operators at least in the MS compiler it will prioritize looking at the global one over the one in the supreclass. Nasty !!! similar issues happen with clang and gcc.
I did find I really have to declaare all the possible conflicting operators at the same level so the overload resolution works as expected. ie: all in the same superclass of the subclass, if there are poerators declared in a superclass of the superclass, they will sometimes be ignored it seems if there is some wayward conversion that supplies an argument to one of the overloads at the higher priority ( arrrgh ).
It seems at this point I have resolved all the compile issue - now to get it to link hahaha !!
Assuming your type is cheap to move:
template<class T, class SubT>
class Vec3 {
// this is fine, ie: works
SubT& operator *=(const T &val) & {
x*=val;y*=val;z*=val;
return *this;
}
friend SubT operator*(Vec3 v, T const& t){
v*=t;
return v;
}
friend SubT operator*(T const& t, Vec3 v){
v*=t;
return v;
}
};
A 3 tuple of numbers is almost always cheap to move, as the numbers are either tiny (like 64 bits) and trivially copyable, or they are going to be a bignum type which uses a cheap to move storage type internally.
This technique creates what I call Koenig operators; non-template operators onky discoverable via ADL from a template class. This has a myriad of advantages over member function operators and non-member template operators. Less so in this simple case, but as a blind recipie it avoids a bunch of pitfalls (like, how having an operator std::string doesn't let you be << streamed).

Is it legal to use variadic templates in operator overloading?

I would like to be able to write something along these lines:
struct bar {};
template <typename ... Args>
bar operator+(bar, Args ...)
{}
I just checked with clang/gcc and the overloaded operator is picked up both by binary expressions (a+b) and unary expressions (+a), as I would expect. However operators are more restricted than normal functions, in the sense that - for instance - you cannot overload operator+() with three arguments.
Is the usage above legal and portable?
EDIT To give a bit of context, I am clearly not expecting to be able to define variadic operators or anything of the sort. The reason I am interested in this is for a ugly hack: I would like to make some operators variadic so that I can "override" them with other non-variadic implementations. Since variadic templates are considered to be less specialised than non-variadic templates in the function template overloading rules, I could override a variadic operator with a non-variadic one. Yes it's pretty horrid :)
First off, the definition fine, because there exist valid specializations with non-empty packs1.
Now, specific expressions a+b or +a are i.a. transformed into non-member calls of the form operator+(a, b) and operator+(a), respectively ([over.match.oper]/2). Name lookup then finds the operator function template, whose specialization becomes part of the candidates. Finally, [over.match.oper]/6 just delegates to overload resolution as usual:
The set of candidate functions for overload resolution is the union of
the member candidates, the non-member candidates, and the built-in
candidates. The argument list contains all of the operands of the
operator. The best function from the set of candidate functions is
selected according to 13.3.2 and 13.3.3.
Your code will also work as intended, since overload resolution and partial ordering will respect the operator function template like all others.
1 declaring the above for unary operators, except perhaps postfix -- and ++, is ill-formed, no diagnostic required. Cf. [temp.res]/(8.2).
The standard restricts the number of arguments (and the presence of default arguments) for operator functions, in [over.oper]:
8 - An operator function cannot have default arguments ([dcl.fct.default]), except where explicitly stated below. Operator
functions cannot have more or fewer parameters than the number required for the corresponding operator,
as described in the rest of this subclause.
However, what you have declared is an operator function template, which has no such restrictions. This means that your code is fine; the use of unary or binary + will be transformed into a call to operator+ with one or two arguments and an appropriate instantiation of your template will be generated accordingly.
It would be illegal if you were to specialize or explicitly instantiate the operator function template with an illegal number of arguments, since ([over.oper]):
1 - [...] A specialization of an operator function template is also an operator
function. [...]
Note that a similar effect obtains if we write a non-variadic operator function template that can be instantiated with incorrect types:
template<class T> int operator+(T, T) { return 0; } // OK
struct bar {}; template int operator+(bar, bar); // OK
template int operator+(int, int); // Error is here

Why are the STL functors themselves templated and not their function call operator?

The STL functors are implemented like this:
template<class T>
struct less{
bool operator()(T const& lhs, T const& rhs){
return lhs < rhs;
}
};
This makes us mention the (possibly long) type everytime we create such a functor. Why are they not implemented like shown below? Any reasons?
struct less{
template<class T>
bool operator()(T const& lhs, T const& rhs){
return lhs < rhs;
}
};
That would make them usable without any mentioning of (possibly long) types.
It would also make it impossible to specialize them for user defined types.
They are supposed to be a customization point.
To summarize the discussions in the comments:
Although it is technically possible to do like Xeo suggests, the language standard doesn't allow it.
It is very hard to write a working class template if users are allowed to specialize individual functions of the template. In some cases it might however be a good idea to specialize the whole class for a user defined type.
Therefore the C++98 standard writes (17.4.3.1):
It is undefined for a C++ program to add declarations or definitions to namespace std or namespaces within namespace std unless otherwise specified. A program may add template specializations for any standard library template to namespace std.
As it isn't "otherwise specified" that Xeo's code is allowed, we are to understand that it is not. Perhaps not totally obvious! Or that "template specializations" only apply to classes.
The new C++11 standard has had this part expanded, and spells it out in more detail (17.6.4.2):
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly
prohibited.
The behavior of a C++ program is undefined if it declares
— an explicit specialization of any member function of a standard library class template, or
— an explicit specialization of any member function template of a standard library class or class template, or
— an explicit or partial specialization of any member class template of a standard library class or class template.
A program may explicitly instantiate a template defined in the standard library only if the declaration depends on the name of a user-defined type and the instantiation meets the standard library requirements for the original template.
Maybe:
std::multiset<long, std::less<int> > moduloset;
Odd thing to do, but the point is that std::less<int>, std::less<long>, std::less<unsigned int> implement different mathematical functions which produce different results when passed (the result of converting) certain argument expressions. Various algorithms and other standard library components work by specifying a functor, so it makes sense to me that there are different functors to represent those different mathematical functions, not just different overloads of operator() on one functor.
Furthermore, a functor with a template operator() can't be an Adaptable Binary Predicate, since it doesn't have argument types (an argument can have any type). So if std::less were defined as you suggest then it couldn't participate in the stuff in <functional>.
Also on a highly speculative note -- std::less was probably designed before support for template member functions was at all widespread, since there are various notes in the SGI STL documentation that say, "if your implementation doesn't support member templates then this isn't available". For such a simple component there would, I guess, be an incentive to do something that works today. Once it exists, the standardization could then have removed it in favour of something else, but was it worth disrupting existing code? If it was that big a deal, then either you or the standard could introduce a flexible_less functor as you describe.
Finally, why
template<class T>
bool operator()(T const& lhs, T const& rhs){
return lhs < rhs;
}
rather than
template<class T, class U>
bool operator()(T const& lhs, U const& rhs){
return lhs < rhs;
}
For user-defined types, the two might not be the same. Yes, this is an unfair question, since I don't know why there's no two-template-argument version of std::less ;-)

C++ - What is the purpose of function template specialization? When to use it?

Learning C++, came upon function templates. The chapter mentioned template specialization.
template <> void foo<int>(int);
void foo( int );
Why specialize when you can use the second? I thought templates were suppose to generalize. What's the point of specializing a function for a specific data type when you can just use a regular function?
Obviously, template specialization exists for a reason. When should it be used? I read Sutter's "Why not Specialize..." article but I need more of a layman's version since I'm just learning this stuff.
The main difference is that in the first case you are providing the compiler with an implementation for the particular type, while in the second you are providing an unrelated non-templated function.
If you always let the compiler infer the types, non-templated functions will be preferred by the compiler over a template, and the compiler will call the free function instead of the template, so providing a non-templated function that matches the arguments will have the same effect of specializations in most cases.
On the other hand, if at any place you provide the template argument (instead of letting the compiler infer), then it will just call the generic template and probably produce unexpected results:
template <typename T> void f(T) {
std::cout << "generic" << std::endl;
}
void f(int) {
std::cout << "f(int)" << std::endl;
}
int main() {
int x = 0;
double d = 0.0;
f(d); // generic
f(x); // f(int)
f<int>(x); // generic !! maybe not what you want
f<int>(d); // generic (same as above)
}
If you had provided an specialization for int of the template, the last two calls would call that specialization and not the generic template.
I personally can see no benefit from specializing a function template. Overloading it by either a different function template or a non-template function is arguably superior because its handling is more intuitive and it's overall more powerful (effectively by overloading the template, you have a partial specialization of the template, even though technically it's called partial ordering).
Herb Sutter has written an article Why not specialize function templates? where he discourages specializing function templates in favour of either overloading them or writing them so that they just forward to a class template's static function and specializing the class template instead.
You can use specialization when you know for a specific class the generic method could be efficient.
template<typename T>
void MySwap(T& lhs, T& rhs)
{
T tmp(lhs);
lhs = rhs;
rhs = tmp;
}
Now for vectors my swap will work, but is not very effecient. But I also know that std::vector implements its own swap() method.
template<>
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
Please don;t compare to std::swap which is a lot more complex and better written. This is just an example to show that a generic version of MySwap() will work but is may not always be efficient. As a result I have shown how it can be made more efficient with a very specific template specialization.
We can also of course use overloading to achieve the same effect.
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
So the question if why use template specialization (if one can use overloading). Why indeed. A non template function will always be chosen over a template function. So template specialization rules are not even invoked (which makes life a lot simpler as those rules are bizarre if you are not a lawyer as well as a computer programmer). So let me thing a second. No can't think of a good reason.
I find it very important. You can use this as you would use a virtual method. There would be no point in virtual methods unless some of them were specialized. I have used it a lot to differentiate between simple types (int,short,float) and objects, object pointers and object references.
An example would be serialize/unserialize methods that would handle objects by calling the objects serialize/unserialize method, while simple types should be written directly to a stream.
One case for template specialization which is not possible with overloading is for template meta-programming. The following is real code from a library that provides some of it services at compile time.
namespace internal{namespace os{
template <class Os> std::ostream& get();
struct stdout{};
struct stderr{};
template <> inline std::ostream& get<stdout>() { return std::cout; }
template <> inline std::ostream& get<stderr>() { return std::cerr; }
}}
// define a specialization for os::get()
#define DEFINE_FILE(ofs_name,filename)\
namespace internal{namespace os{ \
struct ofs_name{ \
std::ofstream ofs; \
ofs_name(){ ofs.open(filename);} \
~ofs_name(){ ofs.close(); delete this; } \
}; \
template <> inline std::ostream& get<ofs_name>(){ return (new ofs_name())->ofs; } \
}} \
using internal::os::ofs_name;
Multiple overloads on the same name do similar things. Specializations do the exact same thing, but on different types. Overloads have the same name, but may be defined in different scopes. A template is declared in only one scope, and the location of a specialization declaration is insignificant (although it must be at the scope of the enclosing namespace).
For example, if you extend std::swap to support your type, you must do so by specialization, because the function is named std::swap, not simply swap, and the functions in <algorithm> would be quite right to specifically call it as ::std::swap( a, b );. Likewise for any name that might be aliased across namespaces: calling a function may get "harder" once you qualify the name.
The scoping issue is confused further by argument-dependent lookup. Often an overload may be found because it is defined in proximity to the type of one of its arguments. (For example, as a static member function.) This is completely different from how the template specialization would be found, which is by simply looking up the template name, and then looking up the explicit specialization once the template has been chosen as the target of the call.
The rules of ADL are the most confusing part of the standard, so I prefer explicit specialization on the priciple of avoiding reliance on it.