operator overloading for a class template specialization - c++

I got stuck with a confusing problem here and i couldnt find any solution so far:
The linker complains about a multiple definition of an overloaded non-member operator==.
Imagine the following situation:
template <class T>
struct MyPtr
{
T* val;
...
}
template <class T> bool operator==(MyPtr<T> const & lhs, MyPtr<T> const & rhs)
{ return *lhs.val == *rhs.val; }
template <class T> bool operator==(MyPtr<T> const & lhs, T* const & rhs)
{ return *lhs.val == *rhs;}
So far so good, everything works like a charme, but as i tried to specialize my class to react to a char* in specific way things get weird:
template <>
struct MyPtr<char>
{
char* val;
...
}
//Now each of these functions result in a multiple definition error of the Linker,
//and i dont get why:
//bool operator== (MyPtr<char> const& lhs, MyPtr<char> const& rhs)
//{ return strcmp(lhs.val,rhs.val) == 0;}
//template <> bool operator==<char> (MyPtr<char> const& lhs, MyPtr<char> const& rhs)
//{ return strcmp(lhs.val,rhs.val) == 0;}
So what am i doing wrong here? The ordering in my code is as it is written here. Moving these function definitions above the Class specialization result in the error:
Error : specialization of 'MyPtr<char>' after instantiation
Error : redefinition of 'class MyPtr<char>'
Please notice i have to use GCC 4.1.2 . I hope its not a compiler problem here... again...

A function definition should only appear in a header file if:
It has been declared with the inline keyword, OR
It is defined within a class definition, OR
It involves at least one template parameter
(Those are among the cases where the multiple-identical-definitions version of ODR applies.)
So inline is not usually required with template functions. But an explicit specialization doesn't actually have any template parameters, so you should mark it inline if you want it in the header file.

Shouldn't this
template <> bool operator==<char> (MyPtr<char> const& lhs, MyPtr<char> const& rhs)
{ return strcmp(lhs.val,rhs.val) == 0;}
be
template <> bool operator==<char> (MyPtr<char> const& lhs, char* const& rhs)
{ return strcmp(lhs.val,rhs) == 0;}
?
Thanks to jogojapan for the corrections

Related

Problems overloading operator== of template sub class

I've problems overloading operator==, different compiler errors using VC++(2015) and g++ 5.4.0 (--std==c++14). Here's the code (this is just an extract of a more complex situation in my real code base):
#include <vector>
template<typename T>
struct A {
struct B {
std::vector<T> _elements;
// Internal cmp op.
bool operator==(const B &other) {
return _elements == other._elements;
}
};
std::vector<B> _entries;
};
// External cmp op.
template<typename T>
inline bool operator==(typename const A<T>::B &l, typename const A<T>::B & r) {
return l._elements == r._elements;
}
int main() {
A<int>::B b0, b1;
b0.operator==(b1); // a
operator==<int>(b0, b1); // b
b0 == b1; // c
std::vector<A<int>::B> v0, v1;
std::equal(v0.begin(), v0.end(), v1.begin()); // d
v0 == v1; // e
return 0;
}
I do not add the error messages, because I have the german version of VC++ and the g++ errors span over many lines.
VC++ gives an error on (e). I don't understand why, because vector<>::operator== seems to call std::equal internally and (d) compiles fine. Why does this fail?
g++ fails to accept my external operator==(), so totally fails to compile this short code. I have no idea how to write an external operator==() for A<T>::B that works with both compilers.
I haven't tried clang yet.
Many thanks.
There were two errors in your program:
// Internal cmp op.
bool operator==(const B &other) const {
///// <- here
return _elements == other._elements;
}
should be a const member and the keyword const cannot appear just behind the typename:
// External cmp op.
template<typename T>
inline bool operator==(typename A<T>::B const& lhs, typename A<T>::B const& rhs)
///// <- here -> ////
{
return lhs._elements == rhs._elements;
}
Live Example
Note that the placement of const is usually fairly liberal in C++, e.g. you can write both const typename A<T>::B & lhs and typename A<T>::B const& lhs, but the form you chose, typename const A<T>::B & lhs is not allowed.
Also note that you want to write either a member operator== or a non-member operator==, but never both. In your case, because T is not deducible in typename A<T>::B, you have to write the ugly operator==<int>(b0, b1) to select the non-member.
I would remove the non-member template operator== and add to your class template A<T> a non-member
bool operator==(const A &other) const {
return _entries == other._entries;
}
so that you can also compare objects of A<int>. Note that this will call the standard library operator== for std::vector which in turn will call your operator== for B.

C++ invalid operands to binary expression

I'm facing a curious compilation error in C++11.
I have a templated class that define an enum class:
template <typename Type>
class stats {
public:
// ...
enum class stat {
AVERAGE = (1 << 0),
STANDARD_DERIVATION = (1 << 1),
// ...
};
// ...
};
I currently want to use this enum in bitwise operations.
For example, here is an example of the usage of that enum:
template <typename Type>
void
stats<Type>::build(stat stats) {
if (stats & stat::AVERAGE)
this->build_average();
if (stats & stat::STANDARD_DEVIATION)
this->build_standard_deviation();
if (stats & stat::PERCENTILES)
this->build_percentiles();
if (stats & stat::LIMITS)
this->build_limits();
}
where we can call this function like this stats.build(stat::AVERAGE | stat::LIMITS).
In order to use the & or the | operators on that enum without having to manually cast to int each time, I have defined operators:
template<typename T>
using stat_t = typename eip::stats<T>::stat;
template <typename Type>
stat_t<Type>
operator|(const stat_t<Type>& lhs, const stat_t<Type>& rhs) {
return static_cast<stat_t<Type>>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
template <typename Type>
stat_t<Type>
operator&(const stat_t<Type>& lhs, const stat_t<Type>& rhs) {
return static_cast<stat_t<Type>>(static_cast<int>(lhs) & static_cast<int>(rhs));
}
However, if I try to compile I get the following error:
error: invalid operands to binary expression ('eip::stats<double>::stat' and 'eip::stats<double>::stat')
if (stats & stat::PERCENTILES)
~~~~~ ^ ~~~~~~~~~~~~~~~~~
candidate template ignored: couldn't infer template argument 'Type'
operator&(const stat_t<Type>& lhs, const stat_t<Type>& rhs) {
^
I don't see why my overload is ignored. It seems that the compiler get the right types for both lhs and rhs (eip::stats<double>::stat) but it couldn't infer the template...
Moreover:
Explicitly calling the operator works (operator&<Type>(stats, stat::AVERAGE);)
I thought the problem was coming from the return type, but calling stat a = stats & stat::AVERAGE; doesn't work (same error as earlier).
Any idea?
There are two things wrong with your code.
This is a non-deducible context:
template <typename Type>
stat_t<Type>
operator&(const stat_t<Type>& lhs, const stat_t<Type>& rhs) { ... }
The idea is the same as if you had wrote:
template <typename T>
void foo(typename cls<T>::type ) { ... }
The compiler can't figure out what T could be there unless you tell it too. So you'd have to define your operator& in a place where we don't actually need to do deduction: make it a friend operator in the class itself:
friend stat operator&(const stat& lhs, const stat& rhs) { ... }
Once we fix that, we get to the other problem, which is that a stat isn't contextually convertable to bool so this expression:
if (stats & stat::AVERAGE)
won't compile. For that, you may want to have your operator& return an int or bool, or using this answer's idea, add an operator! and use it twice.

Accepting templated arguments in function signature regardless of actual instantiation

the title may be a bit confusing so let me elaborate.
Say, I have a class template<bool is_const> foo that can take one of two forms, const or non-const based on the template parameter. This class has some operators overloaded like
bool foo<is_const>::operator==(const foo<is_const> &other) const {
return this->a == other.a;
}
The actual return value is irrelevant here. The point is I have quite a few of those operators and for none of them does it really matter what the value of is_const is for either of the two operands. So, I would like to avoid having to duplicate each operator (once for is_bool==true and once for is_bool==false). Is it possible to define the function in a way that it doesn't really matter what value is_bool has? Kind of like const foo<> &other (which doesn't work, I tried that).
You can make the operator a template:
template <bool B>
bool operator==(const foo<B> & other) const
{
return a = other.a;
}
As you discovered, it is generally preferable to have operator overloads be non-member functions, possibly friends:
template <bool A, bool B>
friend bool operator==(const foo<A> & lhs, const foo<B> & rhs)
{
return lhs.a == rhs.a;
}
you can have template method:
template<bool is_const>
class foo {
public:
template<bool is_another_const>
bool operator==( const foo<is_another_const> &other ) const;
};
Thanks to both of you, #kerek-sb and #slava. Even though your answers didn't really solve the problem it pushed me in the right direction.
The problem with your solutions is that &other is not necessarily the same class as this any more and thus has no access to private members, which is unfortunately crucial for the comparison operators to work. So I played around with making the function a friend. What I arrived at is this:
template <bool lhs_const, bool rhs_const>
friend bool operator==(const _Iterator<lhs_const>& lhs, const _Iterator<rhs_const>& rhs) {
return (lhs.m_pos == rhs.m_pos) && (lhs.m_buffer == rhs.m_buffer);
}
The friend keyword gives access to private members for both template instantiations. It's not technically a member function any more but that doesn't really matter much.

Overloading operator <

I experts, once again while practicing online, i encountered another problem. This is regarding function template. I am able to create the template but i am not sure how to overload appropriate operator. Please advise.
Question
A function template largestOfTree to return the largest of 3 elements of the same parameterised type. To what class can the function template be applied? Write a class trainEngine with fields for name,model,mass. Overload the appropriate operator so the largestOfThree function template can be applied to three trainEngine objects.
So far ?
template<class T>
bool largestOfThree(T t1, T t2, T t3){
if(t1<t2&&t2<t3){
return true;
}else{
return false;
}
}
trainEngine
class trainEngine {
private:
string name;
string model;
string mass;
public:
friend bool operator<(trainEngine const& lhs) {
if (lhs.name<lhs.model&&lhs.model<lhs.mass){
return true;
}
};
A friend operator< is going to be non-member and should thus be binary. Moreover, you forgot the return type. You likely want:
friend bool operator<(trainEngine const& lhs, trainEngine const& rhs) {
// implementation
}
This would go where your operator< declaration is currently.
Here is a list of idiomatic signatures for operator overloads, and a more elaborate explanation of what juanchopanza mentioned in the comments. Note that the non-member operators can be defined within the class body if they are marked as friends. (They are still non-member functions if you do this.)
If you overload operator '<', you should also overload operator '>'
and you have to write return type bool also.
friend bool operator<(trainEngine const& obj1, trainEngine const& obj2)
In fact, it’s convention in most code to prefer the usage of < over > But more generally, always overload the complete set of related operators; in your case, this would probably also be ==, !=, <= and >=.
Let me note that currently your implementation only depends on the right-hand-side (which you call lhs!). It is surely not what you want.
I think you wanted something like this:
bool operator<(trainEngine const& rhs) {
if(name!=rhs.name)
return(name<rhs.name);
if(model!=rhs.model)
return (model<rhs.model);
return (mass<rhs.mass);
}
or the friend version:
//within the class
friend bool operator<(trainEngine const& lhs, trainEngine const& rhs);
//outside the class
bool operator<(trainEngine const& lhs, trainEngine const& rhs) {
if(lhs.name!=rhs.name)
return(lhs.name<rhs.name);
if(lhs.model!=rhs.model)
return (lhs.model<rhs.model);
return (lhs.mass<rhs.mass);
}

What are C++ non-template members as used in the Barton-Nackman trick?

From wikipedia:
// A class template to express an equality comparison interface.
template<typename T> class equal_comparable
{
friend bool operator==(T const &a, T const &b) { return a.equal_to(b); }
friend bool operator!=(T const &a, T const &b) { return !a.equal_to(b); }
};
class value_type
// Class value_type wants to have == and !=, so it derives from
// equal_comparable with itself as argument (which is the CRTP).
: private equal_comparable<value_type>
{
public:
bool equal_to(value_type const& rhs) const; // to be defined
};
This is supposed to be the Barton-Nackman, that could achieve compile-time dimensional analysis (checking if some operations applied to variables end up in comparable numbers, like speed comparable to space/time but no acceleration).
Could anyone explain me how, or at least explain me what are the NON-TEMPLATE members?
Thanks
The rules of the language have changed since the pattern was invented, although care was taken not to break it. In other words, as far as I can tell, it still works but for different reasons than it originally did. I don't think I would base an attempt at dimensional analysis on this pattern as I think there are better ways of doing that today.
I also think the example is too trivial to be helpful. As already stated the instantiation of equal_comparable<value_type> causes operator== and operator!= for value_type to appear. Since they are non-members it doesn't matter that the inheritance is private, they're still eligable for selection when resolving a call. It's just hard to see the point in this example. Let's say however, that you add a template parameter to equal_comparable and a few other things:
template<typename U, typename V> class equal_comparable
{
friend bool operator==(U const &a, V const &b) { return a.equal_to(b); }
friend bool operator!=(U const &a, V const &b) { return !a.equal_to(b); }
};
class some_other_type
{
bool equal_to(value_type const& rhs) const;
};
class value_type
: private equal_comparable<value_type>, // value_type comparable to itself
private equal_comparable<some_other_type> // value_type comparable to some_other_type
{
public:
bool equal_to(value_type const& rhs) const;
bool equal_to(some_other_type const& rhs) const;
};
Disclaimer: I have no idea if this is the way it's supposed to be used but I'm reasonably sure that it would work as described.
These are actually nontemplate nonmembers - the comparison operators in the base template - they get used by the ADL for the derived class. A template member would be something like:
class C
{
...
template < typename T > void DoGreatStuff( T t ) { ... }
...
};
The instantiation of equal_comparable<value_type> in value_type class causes the compiler to generate two comparison functions:
friend bool operator==(value_type const &a, value_type const &b) { return a.equal_to(b); }
friend bool operator!=(value_type const &a, value_type const &b) { return !a.equal_to(b); }
These functions are nontemplate since they do not depend on any template parameter, but they are also nonmembers since they are declared as friend.