I want to know if I can return a subclass object through an overloaded operator from my superclass.
#include <stdio.h>
#include <iostream>
using namespace std;
struct AndSpecification;
struct Specification{
virtual bool is_satisfied(int i) = 0;
AndSpecification operator&& (Specification & other){
return AndSpecification(*this, other);
}
};
struct Specification1 : Specification{
int k;
Specification1(int k) : k(k){}
bool is_satisfied(int i){
if (i > k)
return true;
return false;
}
};
struct Specification2 : Specification{
int k;
Specification2(int k) : k(k){}
bool is_satisfied(int i){
if (i < k)
return true;
return false;
}
};
struct AndSpecification : Specification{
Specification& first;
Specification& second;
AndSpecification(Specification& first, Specification& second) : first(first), second(second){}
bool is_satisfied(int i) override{
return first.is_satisfied(i) && second.is_satisfied(i);
}
};
I think that the result is that I can't use the constructor of my subclass because it is not yet defined. The error messages are:
main.cpp: In member function ‘AndSpecification Specification::operator&&(Specification&)’:
main.cpp:20:56: error: return type ‘struct AndSpecification’ is incomplete
AndSpecification operator&& (Specification & other){
^
main.cpp:21:45: error: invalid use of incomplete type ‘struct AndSpecification’
return AndSpecification(*this, other);
Your incomplete forward class declaration cannot be used in this manner until the class is fully defined. Incomplete (forward) class declaration can be used in certain cases, but this is not one of them.
A C++ compiler reads the source in order, from start to finish. When it sees your operator, it has no idea what this mysterious class is, that it's returning. It has not been defined yet. It only gets defined later, in the header/source file.
You need to declare the class method, and then define it only after the class it's returning is fully defined:
// ...
struct Specification{
virtual bool is_satisfied(int i) = 0;
AndSpecification operator&& (Specification & other);
};
// After AndSpecification is declared, later:
inline AndSpecification Specification::operator&& (Specification & other){
return AndSpecification(*this, other);
}
As an alternative to inline, put the definition of the operator method into one of the translation units.
Whenever the compiler must know the size of a type, it must be defined. A declaration is not enough for constructing a type.
In your case, the simple fix is to make operator&& a free function and move it to the bottom:
AndSpecification operator&& (Specification & left, Specification & right){
return AndSpecification(left, r)ight;
}
In my opinion, free binary operators are better than member functions.
You've implemented an inline function definition before completing the definition of one of the classes you're using in the function. The compiler knows there's a struct AndSpecification but it doesn't know that the particular constructor you're using exists. Declare your method in the class but don't define it until after the definition of AndSpecification.
struct Specification{
virtual bool is_satisfied(int i) = 0;
AndSpecification operator&& (Specification & other);
};
struct AndSpecification : Specification { ... }
inline Specification::operator&& (Specification & other) {
return AndSpecification(*this, other);
}
Related
I'm getting the following error:
main.cpp:18:5: error: 'Iterator' does not name a type
18 | Iterator begin() {
| ^~~~~~~~
With this code:
#include <iostream>
#include <iostream>
#include <memory>
#include <fstream>
#include <filesystem>
using namespace std;
class Numbers {
private:
int current;
int end;
public:
Numbers(int end) : current(0), end(end) {}
Iterator begin() {
return Iterator(this);
}
bool operator==(const Numbers& other) const {
return current == other.current && end == other.end;
}
bool operator!=(const Numbers& other) const {
return !(other == *this);
}
class Iterator {
private:
Numbers* range;
public:
using value_type = int;
using difference_type = ptrdiff_t;
using pointer = int*;
using reference = int&;
using iterator_category = input_iterator_tag;
Iterator(Numbers* range) : range(range) {}
int operator*() const {
return range->current;
}
int* operator->() const {
return &range->current;
}
bool operator==(const Iterator& other) const {
return other.range == range;
}
bool operator!=(const Iterator& other) const {
return !(*this == other);
}
Iterator& operator++() {
range->current++;
return *this;
}
};
};
It turns out that moving the begin function under the nested Iterator class makes this compile.
But it's odd - don't nested classes follow the same access rules as any other member, meaning no need for forward-references?
I searched the other questions on the site regarding this exact issue, didn't seem to find an answer.
From a comment to the question
Also - I have no problem calling member function f in member function
q where f is defined after q. Can you explain why the latter example
is different than the situation described in this question?
According to the C++ 20 Standard (11.4 Class members)
6 A complete-class context of a class is a
> (6.1) — function body (9.5.1),
(6.2) — default argument (9.3.3.6),
(6.3) — noexcept-specifier (14.5), or
(6.4) — default member initializer
within the member-specification of the class
So inside the complete class context the name of the function f is visible within the body of the function q.
However the inner class is declared outside the complete class context. So according to the C++ 20 Standard (6.5.1 Unqualified name lookup)
7 A name used in the definition of a class X23 outside of a
complete-class context (11.4) of X shall be declared in one of the
following ways:
> (7.1) — before its use in class X or be a member of a base class of X
(11.8), or
...
So the name of the inner class Iterator must be declared before its using as a return type of a member function.
Instead of the name Iterator you could use for example the place holder auto as the return type.
auto begin() {
return Iterator(this);
}
According to boost documentation - proper usage of boost::operators is to derive from it:
class A : boost::operators<A>
{
public:
bool operator < (const A&) const { return false; }
};
Now, I can use > and <= and >= because all of these operators can be implemented with <, see code snippet from boost:
template <class T, class B = operators_detail::empty_base<T> >
struct less_than_comparable1 : B
{
friend bool operator>(const T& x, const T& y) { return y < x; }
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
};
And finally less_than_comparable1 is one of boost::operators base class.
PROBLEM:
But adding such inheritance is not always convenient. E.g. this inheritance means I have to add constructor(s) to some structs, otherwise all old code, such as A{1} stops compiling:
struct A : boost::operators<A>
{
A() = default;
A(int a, int b = 0) : a(a), b(b) {}
int a;
int b;
};
bool operator < (const A&, const A&);
I tried several ways: inner class, static members of boost::operators<A> but it seems that only inheritance works.
I accept an answer that shows the way how to use boost::operators without inheritance.
I can also accept an answer, that explains why this inheritance is needed.
Ok, let's simplify a little this example, why I need inheritance in this very example below to get operator > from operator <?
template <typename A>
struct GtOperator
{
friend bool operator > (const A& l, const A& r)
{
return r < l;
}
};
struct A : private GtOperator<A>
{
bool operator < (const A&) const
{
return false;
}
};
int main() {
if (A{} > A{})
{
return -1;
}
}
Nothing else seems to work, e.g. this way does not work:
struct A
{
GtOperator<A> dummy;
bool operator < (const A&) const
{
return false;
}
};
Is it possible not to inherit from boost::operators, but still use it?
No, basically. It's intended to be inherited from. The reason it works is because argument-dependent lookup will only look for friend functions and function templates in associated classes ([basic.lookup.argdep]/4) - which are going to be A and A's base classes. If boost::operators<A> isn't a base class of A, its friend functions won't be found by name lookup.
Even with new aggregate initialization rules in C++17, A{1,2} would break because you'd have to write A{{},1,2}.
Your best bet is probably to write a macro that functions as a mixin that effectively accomplishes the same thing. So the ordering ones would be:
#define LESS_THAN_COMPARABLE(T) \
friend bool operator>(const T& x, const T& y) { return y < x; } \
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); } \
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
class A
{
public:
bool operator < (const A&) const { return false; }
LESS_THAN_COMPARABLE(A)
};
Yes, that kind of sucks. (Also these could be defined as non-member functions as well, just drop the friend and put the macro invocation outside of the class).
The other alternative, besides adding constructors and writing macros, is to hope that <=> comes to fruition and then wait a few years to be able to use it.
Test.h:
class Test {
private:
int value;
public:
Test();
int getValue();
void setValue(int value);
bool operator >(Test &l) {
if (value > l.value) {
return true;
}
return false;
}
};
Can this cause any problems? If yes, what is the right way to implement it into a cpp file? If I attempt to implement it into a cpp file, I get an error saying that the number of arguments (because the function is now not inside the class?).
I'd say for such trivial functions this is the ideal way to do it because it allows the compiler to inline them, removing the function overhead.
But you should make the functions const where possible.
So:
class Test {
private:
int value;
public:
Test();
int getValue();
void setValue(int value);
bool operator >(const Test &l) const { // be const correct!
if (value > l.value) {
return true;
}
return false;
}
};
The function does not modify the data members at all so I have marked it const. Also the parameter is not changed so that too I have marked const.
If you do want to implement it into a separate cpp file then you need to qualify it with the class name:
Test.h
class Test {
private:
int value;
public:
Test();
int getValue();
void setValue(int value);
bool operator >(const Test &l) const; // declare only
};
Test.cpp
// Qualify the name with Test::
bool Test::operator >(const Test &l) const { // be const correct!
if (value > l.value) {
return true;
}
return false;
}
Also you can be a little more succinct with these functions:
// Qualify the name with Test::
bool Test::operator >(const Test &l) const { // be const correct!
return value > l.value;
}
In theory you should be making class objects as small as possible, and be doing everything you can in small related non-member functions. The difference I suspect you're getting bitten by is that a non-static member function defined inside a class always has an 'invisible' first/last parameter (the this pointer). You may forget that, but the compiler won't...
Hi I'm having some trouble with inhertance and operator overloading and I'm hoping you guys can give me some clarity.
I have the following classes:
template<typename Type>
class Predicate{
public:
Predicate() {};
virtual ~Predicate(){};
virtual bool operator()(const Type & value) = 0;
virtual bool operator()(const Type * value){ //<-- this is the operator thats not working
return (*this)(*value);
};
};
template<typename Type>
class Always : public Predicate<Type>{
public:
bool operator()(const Type & value){return true;}
~Always(){};
};
Now I want all my predicates to accept both references and pointers, but when I test the classes in:
int main(){
Always<int> a;
int i = 1000;
a(&i);
system("pause");
return 1;
}
I receive the following error:
test.cpp: In function 'int main()':
test.cpp:10:6: error: invalid conversion from 'int*' to 'int' [-fpermissive]
a(&i);
^
In file included from test.cpp:2:0:
predicates.h:22:7: error: initializing argument 1 of 'bool Always<Type>::operator()(const Type&) [with Type = int]' [-fpermissive]
bool operator()(const Type & value){return true;}
This is because when you are declaring:
bool operator()(const Type & value){return true;}
in the subclass, you are hiding/shadowing any other overload of the operator in the superclass.
If you add:
using Predicate<Type>::operator();
Live demo
in the subclass, everything will work fine.
On a side note, I think that allowing both const& and const* is a design smell. You should just allow the const& version and let the user of your class do *ptr if they have a ptr pointer.
Templates and operator overloading obfuscate the real problem here. Look at this small piece of code which yields the same error:
void f(int &);
int main()
{
int *ptr;
f(ptr);
}
The compiler won't let you pass a pointer where a reference is expected. This is what you try to do with your derived class. As you operate on a concrete Always, the base versions of operator() are not considered.
Look how the situation changes when you operate instead on a pointer (or reference) to the base class:
int main(){
Predicate<int> *ptr = new Always<int>;
int i = 1000;
(*ptr)(&i);
delete ptr;
}
This compiles fine because the base-class operators are now considered for overload resolution. But this is just to make you understand the problem better. The solution is to apply the Non-Virtual Interface Idiom. Make your operators non-virtual and implement them in terms of private virtual functions:
template<typename Type>
class Predicate{
public:
Predicate() {};
virtual ~Predicate(){};
bool operator()(const Type & value) { return operatorImpl(value); }
bool operator()(const Type * value) { return operatorImpl(value); }
private:
virtual bool operatorImpl(const Type & value) = 0;
virtual bool operatorImpl(const Type * value) {
return (*this)(*value);
}
};
template<typename Type>
class Always : public Predicate<Type>{
public:
~Always(){};
private:
bool operatorImpl(const Type & value){return true;}
};
Just idly curious why the compare function for stl::sort can't be a static member?
I have a small little helper class foo that is declared and defined in a header, but now I have to create a foo.cpp file for the implementation of cmp() so it isn't multiply defined.
I also have to think of a suitably decorated name so fooCmp() doesn't clash with any other cmp().
Because it has no access to any member variables any compare operation that needs access to some other value (eg. sort by distance from foo.bar) needs the complex bind2nd call.
I am not sure what you are complaining about:
std::sort(begin,end) // use operator<
std::sort(begin,end,order) // Where order is a functor
So order can be:
A function
A static member function
Or an object that behaves like a function.
The following works for me:
class X
{
public: static bool diff(X const& lhs,X const& rhs) { return true;}
};
int main()
{
std::vector<X> a;
std::sort(a.begin(),a.end(),&X::diff);
}
But if the class has some natural ordering then why not just define the operator< for the class. This will allow you the access to the members and will behave nicely for most of the standard containers/algorithms that need to define an ordering.
class X
{
public: bool operator<(X const& rhs) const { return true;}
};
int main()
{
std::vector<X> a;
std::sort(a.begin(),a.end());
}
If you're concerned with a multiply defined compare function, try declaring the function with static linkage. Then the scope of the function does not extend past the compilation unit where it is found.
That said, your compare "function" need not be a function at all, but can instead be a function object. A function object is very much like a function but is implemented as an operator() that takes the appropriate parameters within a regular class. Since it's a regular class, you can pass constructor parameters to the class.
Here is a simple example:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class comparator {
public:
bool operator()(int a, int b) {
return a < b;
}
};
int main(int, char *[])
{
vector<int> a;
a.push_back(1);
a.push_back(3);
a.push_back(2);
sort(a.begin(), a.end(), comparator());
cout << a << endl;
}
actually sounds like the function was
declared in the class,
defined in the header but outside the class without inline linkage
ie something like:
class foo{
public:
static bool compare(const foo& lhs,const foo& rhs);
...
};
bool foo::compare(const foo& lhs,const foo& rhs){
...
}
instead of
class foo{
public:
static bool compare(const foo& lhs,const foo& rhs);
...
};
inline bool foo::compare(const foo& lhs,const foo& rhs){
...
}
the first of which will cause the function to be defined in every compilation unit that
#includes "foo.h"