Let's say I am creating an Abstract Base Class for the purpose of defining a public interface. I want operator+ to be a part of this public interface. It would seem that this is not possible in C++ or that I am missing something.
For example, suppose the code below is a .h file declaring the public interface for an abstract base class named IAbstract. This code does not compile because I cannot declare a function that returns an instance of an abstract base class. This compile error makes sense, but what I don't understand is this: Is there any way to guarantee operator+ will exist in the public interface of IAbstract?
#include <iostream>
// An abstract base class
class IAbstract
{
public:
IAbstract(int value);
virtual ~IAbstract() {}
virtual int SomeOtherFunction() =0;
//This is ok
virtual IAbstract& operator++() =0;
//This will not compile
virtual const IAbstract operator+(const IAbstract& rhs) =0;
//Xcode5 says "Semantic Issue: Return type 'IAbstract' is an abstract class"
};
In addition to the return by value problem, the really problem with your dessign is the way that the C++ language works.
Object oriented languages like Java defines and transmit functionality through class hierarchies, interfaces, and polymorphism. Your code is the typical example of that.
C++ does not work in that way. C++ defines functionality through abstract concepts, and classes only need to fulfill this concepts to be usable in a certain way. How/if a class follows or implements a certain concept depends on its behavior, the implementation of certain functions (Like overloaded operators), etc.
So the C++ way to do what you are trying to achieve is to overload the required operators in a generic way, to ensure all classes that would implement the concept works with it.
In other words, if you are trying to make an addable concept, that is, represent things that could be added with others, a class only have to overload operator+. If a class overloads operator+ its addable. Just simple.
Here is another example: The classic implementation of std::copy():
template<typename IT , typename DEST_IT>
void copy( IT begin , IT end , DEST_IT dest_begin )
{
while( begin != end )
*dest_begin++ = *begin++;
}
In that implementation, whats the type of begin and end? Simple answer: We don't know. Could be anything. But could be anything that must fulfill the requirements of our function, that is: Is dereferenciable, incrementable, and comparable. In other words: Its an iterable type. A type that works (And seems like) an iterator.
So std::copy() works with any ranges represented by iterable things. Could be arrays:
int main()
{
int a[] = { 1,2,3 };
int b[3];
int* begin_a = &a[0];
int* end_a = &a[2];
int* begin_b = &b[0];
//Pointers are an iterable thing, right?:
std::copy( begin_a , end_a , begin_b );
//Or just the common generic way (Which does exactly the same):
std::copy( std::begin( a ) , std::end( a ) , std::begin( a ) );
}
Vectors, lists, etc:
int main()
{
std::vector<int> a = { 1,2,3 };
std::vector<int> b;
//Wooh, the code is exactly the same! Thats why templates are cool.
std::copy( std::begin( a ) , std::end( a ) , std::begin( a ) );
}
More freaking things, like iterators to walk through an stream:
int main()
{
std::vector<int> a = { 1,2,3 };
//Copy a vector to the standard output? Yes we can!
std::copy( std::begin( a ) , std::end( a ) , std::ostream_iterator<int>( std::cout , "\n" ) );
}
1
2
3
And your own classes:
struct numeric_iterator
{
int value;
numeric_iterator( int initial_value = 0 ) : value( initial_value ) {}
//numeric_iterator is an iterable thing because...
//... its dereferenciable
int operator*() const
{
return value;
}
//... its incrementable
numeric_iterator& operator++()
{
++value;
return *this;
}
numeric_iterator operator++(int)
{
numeric_iterator copy( *this );
++(*this);
return copy;
}
//... and its comparable
friend bool operator==( const numeric_iterator& lhs , const numeric_iterator& lhs )
{
return lhs.value == rhs.value;
}
friend bool operator!=( const numeric_iterator& lhs , const numeric_iterator& lhs )
{
return !( lhs == rhs );
}
};
int main()
{
//Tah dah!
std::copy( numeric_iterator( -4 ) ,
numeric_iterator( 5 ) ,
std::ostream_iterator<int>( std::cout , " " )
);
}
-4 -3 -2 -1 0 1 2 3 4
The offending line is:
virtual const IAbstract operator+(const IAbstract& rhs) =0;
That method returns by value, thus copying and creating an object of type IAbstract, which is not allowed. You should change to:
virtual const IAbstract& operator+(const IAbstract& rhs) =0;
That seems to be your intent but an easy oversight.
Somewhere you have: IAbstract variable and you can never actually have an IAbstract, only pointers to it (or references).
It is annoyed because somewhere you try and deal with a IAbstract.
It wants IAbstract* or IAbstract& or IAbstract&& which are all fine (in some form (const and volatile, so forth)).
There you go, you are returning IAbstract from operator++, which makes no sense, because you can never have a IAbstract, just look at something as one.
No, it is not possible guarantee operator+ will exist in the public interface of IAbstract-derived classes because you cannot properly declare operator+ as a pure virtual function.
The trick is to encapsulate the abstract base class, inside a regular type. The solution requires that there is a clone method
class AbstractNumericType
{
public:
virtual AbstractNumericType& operator+=(AbstractNumericType const& other) = 0;
virtual std::unique_ptr<AbstractNumeric> clone() = 0;
virtual ~AbstractNumericType() = default;
};
class NumericType
{
public:
template<class Something>
NumericType(Something value):m_obj{createNumber(value)}
{}
NumericType(NumericType const& other): m_obj{other.m_obj->clone()}
{}
NumericType operator+(NumericType const& other) const
{
auto ret = *this;
(*ret.m_obj) += (*other.m_obj);
return ret;
}
private:
std::unique_ptr<AbstractNumericType> m_obj;
};
Demo: https://gcc.godbolt.org/z/e4v1Tr
The real problem here is how you can implement operator+= when you do not have the concrete type available. You could add multiple overloads (like visitor pattern), or you could use a type switch based on rtti. None of these solutions is really good.
Related
The problem in question is related to the question and discussion found in this SO thread.
The problem is essentially as follows, I have an abstract class called players. Then I have two classes attackers and defenders. Now, I would like to have an unordered container (map, set, etc.) containing all players. For that I need a hash function (which is not the issue as both attackers and defenders have names) and an equality function. The latter is the problem. As discussed in the linked SO thread, it seems to be bad practice to inherit operator== and I can see why.
I now wonder what the idiomatic solution to my problem is. Is it to just have two containers? One for players and one for attackers? Are there other solutions?
Edit:
Yes, I am talking about unordered_* containers. I am aware that I would need to store pointers in the containers rather than objects themselves. For example, I'd have a container std::unordered_set<std::shared_ptr<players>> all_players.
When you instantiate your map, you can specify a comparator:
template< class InputIt >
map( InputIt first, InputIt last,
const Compare& comp = Compare(), /// << this here
const Allocator& alloc = Allocator() );
Reference: https://en.cppreference.com/w/cpp/container/map/map
Then, you don't need to define the equality operator. In any case, in order to store polymorphic objects in a map, you'll need to store pointers.
So, you would need a comparator anyway, in order to compare the objects, not the pointer values.
In order to store multiple different types in the same container, you have to take advantage of polymorphism.
Polymorphism requires you to use pointers to objects instead of actual objects. That's because C/C++ doesn't allow you to make arrays of multiple different types. The best way to do that in modern C++ is to use std::unique_ptr or std::shared_ptr from #include <memory>
To make a polymorphic container you'll need the following:
A common base struct/class that all of your types inherit from.
Some way to interface with subtype-specific methods/members.
This can be a virtual method in the base object, a member of the base object, or you can also use typeid to figure out what type something is at runtime.
#include <iostream>
#include <vector>
#include <memory>
#include <typeinfo>
struct base {
virtual ~base() = default;
virtual int GetValue() const = 0;
};
struct A : base {
int a;
A(const int v) : a{ v } {}
int GetValue() const override { return a; }
void doSomething() const { std::cout << "Hello World!"; }
};
struct B : base {
int b;
int mult;
B(const int v, const int mult) : b{ v }, mult{ mult } {}
int GetValue() const override { return b * mult; }
void doSomethingElse() const { std::cout << "!dlroW olleH"; }
};
int main()
{
std::vector<std::unique_ptr<base>> vec;
vec.emplace_back(std::make_unique<A>(5)); //< insert an object of type A
vec.emplace_back(std::make_unique<B>(8, 2)); //< insert an object of type B
for (const auto& it : vec) {
std::cout << it->GetValue() << '\t';
if (typeid(*it.get()) == typeid(A)) {
((A*)it.get())->doSomething();
}
else if (typeid(*it.get()) == typeid(B)) {
((B*)it.get())->doSomethingElse();
}
std::cout << std::endl;
}
}
Outputs:
5 Hello World!
16 !dlroW olleH
You need a hash function-object that looks through your pointers. The base class can have non-virtual implementations, or equivalently you can have the hasher inspect the public members.
class players {
public:
size_t hash() const;
friend bool operator==(const player & lhs, const player & rhs);
};
using std::unique_ptr<players> players_ptr;
struct players_hash {
size_t operator()(const players_ptr & ptr) { return ptr->hash(); }
};
struct players_equal {
bool operator()(const players_ptr & lhs, const players_ptr & rhs) { return *lhs == *rhs; }
};
std::unordered_set<players_ptr, players_hash, players_equal> all_players;
I'm trying to use emplace() to construct in-place a map<K,V> entry (using Boost). The key object constructor arg gets forwarded through the template magic correctly, but the V object constructor arg becomes const, so it doesn't work.
#include <boost/container/map.hpp>
class A {
public:
/**/ A( int n ) { }
friend bool operator<( const A &a1, const A &a2 ) { return false; }
} ;
class B {
public:
/**/ B( const char *str ) { }
} ;
class C {
public:
/**/ C( B &b ) { }
} ;
int
main( int, char ** )
{
boost::container::map<A,B> m1;
boost::container::map<A,C> m2;
B b( "Foo" );
C c( b ); // <--- this works OK.
m1.emplace( 1, "Hello" );
m2.emplace( 2, b ); // <----- this fails!
}
The Error is:
Error: /usr/local/include/boost/container/detail/pair.hpp:128:38: error: no matching function for call to C::C(const B&), second(::boost::forward<V>(v))
Something about the emplace argument-forwarding turns b into const b in the last line. I know there must be a boost::bla_bla_bla that I can apply to make it work, but I haven't been able to find it.
Can anybody help?
Note that if you compile this using -std=c++11 (or later), this will work. Why this is the case took a bit of digging - I'm using a slightly older version of boost (1.56), but I doubt this has changed much between the two releases.
Using emplace generally requires perfect forwarding. This means all of the arguments are forwarded as via std::forward<Args>(args).... Underneath, this relies on reference collapsing and move semantics - this is all C++11 territory, and has no analog in C++03.
If we dig into the boost code for pair (where it's actually generating the error), then this is the constructor it's attempting to call:
template<class U, class V>
pair(BOOST_FWD_REF(U) u, BOOST_FWD_REF(V) v)
: first(::boost::forward<U>(u))
, second(::boost::forward<V>(v))
{}
Unfortunately, BOOST_FWD_REF (which is in move/core.hpp) is one of the following:
#define BOOST_FWD_REF(TYPE)\
const TYPE & \
//
#define BOOST_FWD_REF(TYPE)\
const TYPE & \
//
When your compiler does not recognise rvalue references, this will then become const TYPE&.
There's a bit of discussion on this on the boost archives list.
The easiest solution is to simply compile with std=c++11.
Is it possible to call operator[] with out using * when I have a pointer to the class ?
class MyClass
{
public:
void operator[](int n)
{
cout<<"In []";
}
};
int main()
{
MyClass *a=new MyClass;
(*a)[2];//work
a[2];//It just do some pointer arithmetic ...too bad :((
}
Yes, you should be able to use the -> operator, like this:
a->operator[] (2);
Demo on ideone.
If all you need is eliminating the asterisk, this should do the trick. If you are aiming for a better readability, this isn't of much help - you need to either avoid the pointer, or to use a regular member function:
class MyClass
{
public:
void operator[](int n)
{
cout<<"In []";
}
// Add a regular function for use with pointers
// that forwards the call to the operator[]
void at(int n) { (*this)[n]; }
};
Now you can write a->at(2);
(Demo on ideone).
template<typename LHS> struct at_lhs_t { LHS lhs; };
static struct at_t {} at;
template<typename LHS>
at_lhs_t<LHS> operator%( LHS&& lhs, at_t )
{ return {std::forward<LHS>(lhs)}; }
template<typename LHS, typename RHS>
auto operator%( at_lhs_t<LHS>&& lhs, RHS&& rhs )
->decltype( (std::forward<LHS>(lhs.lhs))->operator[](std::forward<RHS>(rhs)) )
{ return ( (std::forward<LHS>(lhs.lhs))->operator[](std::forward<RHS>(rhs)) ); }
class MyClass
{
public:
void operator[](int n)
{
std::cout<<"In []";
}
};
int main()
{
MyClass *a=new MyClass;
a %at% 2;
}
live example, but this is probably not what you want either.
In practice, just use the *. The * (as well as ->s) help remind you that the left hand side must be first checked for validity before it can be used in most contexts. After you check that your pointer is valid, you can dereference and store it in a reference for the duration of the current scope, and use [] to your heart's content.
The (*a) brackets get to be a bit annoying. On the other hand, possibly you should also avoid using pointers as much: modern C++ has moved away from using pointers, and would rather wrap things in smart pointers or pImpl wrappers and store the data in value-semantic types.
Then you only deal with pointers inside your smart pointer storage types, and when you want reseatable indirection to resources held elsewhere. Your nice and pretty pImpl wrappers are used more often, and they act like values even if most of their state is held dynamically.
I have a polymorphic interface
struct Interface {
Interface(SomeType& other)
: range([=](){ return other.my_range(); }), /*...*/ {}
Interface(SomeOtherType& other)
: range([=](){ return other.some_range(); }), /*...*/ {}
const std::function<Range(void)> range;
/// ...
};
The elements in both ranges are of the same type (e.g. int), but the types returned by my_range() and by some_range() are different, e.g. one can be a filtered counting range and the other a transformed filtered counting range. For the interface I need a single Range type.
I've tried using boost::any_range but the performance is significantly worse. I would like to avoid having to copy the range elements into a vector and returning the vector instead.
Are there any alternatives to any_range and copying?
Kind of, but not really.
You want to access data sequentially when you don't know how it's stored. You have three options:
Copy the data into a container with known format (the "return vector" option).
Use compile-time polymorphism to choose the correct access method (the way std algorithms do it, not possible due to you using an interface).
Use runtime polymorphism to choose the correct access method.
So the second is not possible due to the constraint that you want to use an interface. The first and the third both come with overhead.
The obvious way of doing the third thing is any_range. But it's not the only way, depending on what you want to do. The problem with any_range is that in a simple for-each loop, there are three virtual calls for every element: the increment, the comparison, and the dereference.
As long as all you want to do is simple for-each iteration, you could reduce the overhead to one virtual call by implementing the loop on the interface level:
struct Interface {
Interface(SomeType& other)
: traverse([=](std::function<void(int)> body) {
for (int i : other.my_range()) body(i);
}) {}
const std::function<void (std::function<void(int)>)> traverse;
};
Of course that only works as long as the ways you use the range are very limited.
If there are only known 2 known types (or fixed number of types), then alternative could be Boost.Variant. Here is sample usage:
#include <boost/variant.hpp>
#include <functional>
struct SomeType
{
typedef int range_t;
range_t my_range() const { return 1; }
};
struct SomeOtherType
{
typedef double range_t;
range_t some_range() const { return 3.14; }
};
typedef std::function<SomeType::range_t (void)> SomeTypeRange;
typedef std::function<SomeOtherType::range_t (void)> SomeOtherTypeRange;
typedef boost::variant<SomeTypeRange, SomeOtherTypeRange> Range;
struct Interface
{
Interface(const SomeType& other)
: range( SomeTypeRange([=](){ return other.my_range(); }) ) {}
Interface(const SomeOtherType& other)
: range( SomeOtherTypeRange([=](){ return other.some_range(); }) ) {}
Range range;
};
struct print_me_visitor : public boost::static_visitor<void>
{
public:
void operator()( const SomeTypeRange& i_st ) const
{
std::cout << "SomeTypeRange: " << i_st() << std::endl;
}
void operator()( const SomeOtherTypeRange& i_sot ) const
{
std::cout << "SomeOtherTypeRange: " << i_sot() << std::endl;
}
};
int main()
{
SomeType st;
SomeOtherType sot;
Interface i1( st );
Interface i2( sot );
boost::apply_visitor( print_me_visitor(), i1.range );
boost::apply_visitor( print_me_visitor(), i2.range );
return 0;
}
I have a struct that's defined like this:
struct Vec3 {
float x, y, z;
}
When I attempted to use std::unique on a std::vector<Vec3>, I was met with this error:
Description Resource Path Location Type
no match for ‘operator==’ in ‘_first._gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* with _Iterator = Vec3*, _Container = std::vector > == _next._gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* with _Iterator = Vec3*, _Container = std::vector >’ ModelConverter line 4351, external location: /usr/include/c++/4.4.6/bits/stl_algo.h C/C++ Problem
I understand the the necessity of the naievite of the compiler in inequality operators and others (in this case, * would almost certainly not be what I mean), but is this a matter of policy, or is there a technical reason for it that I'm not aware of? There's a default assignment operator, so why no default equality operator?
There's no technical reason. Pedantically, you might say this is because C doesn't let you compare two structures with ==, and this is a good reason; that behavior switching when you go to C++ is non-obvious. (Presumably, the reason that C doesn't support that is that field-wise comparison might work for some structs, but definitely not all.)
And just from a C++ point of view, what if you have a private field? A default == technically exposes that field (indirectly, but still). So would the compiler only generate an operator== if there are no private or protected data members?
Also, there are classes that have no reasonable definition of equality (empty classes, classes that do not model state but cache it, etc.), or for whom the default equality check might be extremely confusing (classes that wrap pointers).
And then there's inheritance. Deciding what to do for operator== in a situation of inheritance is complicated, and it'd be easy for the compiler to make the wrong decision. (For example, if this was what C++ did, we would probably be getting questions about why == always succeed when you test equality between two objects that are both descendants of an abstract base class and being used with a reference to it.)
Basically, it's a thorny problem, and it's safer for the compiler to stay out of it, even considering that you could override whatever the compiler decided.
The question of why you have to provide operator== is not the same as the question of why you have to provide some comparison function.
Regarding the latter, the reason that you are required to provide the comparison logic, is that element-wise equality is seldom appropriate. Consider, for example, a POD struct with an array of char in there. If it’s being used to hold a zero-terminated string, then two such structs can compare unequal at the binary level (due to arbitrary contents after the zero bytes in the strings) yet being logically equivalent.
In addition, there are all the C++ level complications mentioned by other answers here, e.g. the especially thorny one of polymorphic equality (you really don’t want the compiler to choose!).
So, essentially, there is simply no good default choice, so the choice is yours.
Regarding the former question, which is what you literally asked, why do you have to provide operator==?
If you define operator< and operator==, then the operator definitions in namespace std::rel_ops can fill in the rest for you. Presumably the reason why operator== is needed is that it would be needlessly inefficient to implement it in terms of operator< (then requiring two comparisons). However, the choice of these two operators as basis is thoroughly baffling, because it makes user code verbose and complicated, and in some cases much less efficient than possible!
The IMHO best basis for comparison operators is instead the three-valued compare function, such as std::string::compare.
Given a member function variant comparedTo, you can then use a Curiously Recurring Template Pattern class like the one below, to provide the full set of operators:
template< class Derived >
class ComparisionOps
{
public:
friend int compare( Derived const a, Derived const& b )
{
return a.comparedTo( b );
}
friend bool operator<( Derived const a, Derived const b )
{
return (compare( a, b ) < 0);
}
friend bool operator<=( Derived const a, Derived const b )
{
return (compare( a, b ) <= 0);
}
friend bool operator==( Derived const a, Derived const b )
{
return (compare( a, b ) == 0);
}
friend bool operator>=( Derived const a, Derived const b )
{
return (compare( a, b ) >= 0);
}
friend bool operator>( Derived const a, Derived const b )
{
return (compare( a, b ) > 0);
}
friend bool operator!=( Derived const a, Derived const b )
{
return (compare( a, b ) != 0);
}
};
where compare is an overloaded function, e.g. like this:
template< class Type >
inline bool lt( Type const& a, Type const& b )
{
return std::less<Type>()( a, b );
}
template< class Type >
inline bool eq( Type const& a, Type const& b )
{
return std::equal_to<Type>()( a, b );
}
template< class Type >
inline int compare( Type const& a, Type const b )
{
return (lt( a, b )? -1 : eq( a, b )? 0 : +1);
}
template< class Char >
inline int compare( basic_string<Char> const& a, basic_string<Char> const& b )
{
return a.compare( b );
}
template< class Char >
inline int compareCStrings( Char const a[], Char const b[] )
{
typedef char_traits<Char> Traits;
Size const aLen = Traits::length( a );
Size const bLen = Traits::length( b );
// Since there can be negative Char values, cannot rely on comparision stopping
// at zero termination (this can probably be much optimized at assembly level):
int const way = Traits::compare( a, b, min( aLen, bLen ) );
return (way == 0? compare( aLen, bLen ) : way);
}
inline int compare( char const a[], char const b[] )
{
return compareCStrings( a, b );
}
inline int compare( wchar_t const a[], wchar_t const b[] )
{
return compareCStrings( a, b );
}
Now, that’s the machinery. What does it look like to apply it to your class …
struct Vec3
{
float x, y, z;
};
?
Well it’s pretty simple:
struct Vec3
: public ComparisionOps<Vec3>
{
float x, y, z;
int comparedTo( Vec3 const& other ) const
{
if( int c = compare( x, other.x ) ) { return c; }
if( int c = compare( y, other.y ) ) { return c; }
if( int c = compare( z, other.z ) ) { return c; }
return 0; // Equal.
}
};
Disclaimer: not very tested code… :-)
C++20 adds this capability:
struct Vec3 {
float x, y, z;
auto operator<=>(const Vec3&) const = default;
bool operator==(X const&) const = default;
}
This is currently only implemented in GCC and clang trunk. Note that currently defaulting operator<=> is equivalent to also defaulting operator==, however there is an accepted proposal to remove this. The proposal suggests having defaulting operator<=> also imply (not be equivalent to as it is today) defaulting operator== as an extension.
Microsoft has documentation on this feature at https://devblogs.microsoft.com/cppblog/simplify-your-code-with-rocket-science-c20s-spaceship-operator/.
What would you like the equality operation to be? All the fields the same? It's not gonna make that decision for you.