I have a question related to operator overloading, and it is easy to define a class as well as its operator overloading function as the following codes illustrate:
typedef std::vector<std::vector<int> > ARRAY;
class ABC
{
public:
ABC():a(0)
{
};
int a;
ABC& operator = (int value)
{
a = value;
return *this;
}
ABC(int value)
{
a = value;
}
};
void obtain_priority_array(const std::vector<double> &weighting, const ABC &priority_array=NULL)
{
}
int main()
{
vector<double> weighting;
weighting.push_back(0.8);
weighting.push_back(0.9);
weighting.push_back(0.6);
weighting.push_back(0.3);
weighting.push_back(0.5);
ABC test;
obtain_priority_array(weighting, test);
return 0;
}
In the above example, class ABC redefined operator = so that the function void obtain_priority_array(const std::vector<double> &weighting, const ABC &priority_array=NULL) can have a default argument const ABC &priority_array=NULL. My question is if the last parameter in the function comes from STL, for example, const std::vector<int> &priority_array=NULL, how can we redefine operator =. Thanks!
EDIT:
void obtain_priority_array(const std::vector &weighting, const std::vector<int> &sample=NULL) failed!
Your misconceptions start with the proposal to add operator= to allow for a default argument of that type. In your example, it is not operator= being called, but ABC(int).
The reason your code isn't being accepted when using std::vector is that NULL translates to 0 (at least it does almost all of the time you'll see it), and the only constructor of std::vector that can take 0, the one taking a count of how many items, is marked explicit.
To fix the immediate problem, the syntax could be changed to:
const std::vector<int> &priority_array = std::vector<int>(0)
However, this introduces different semantics. By your use of NULL, it looks like you were expecting it to represent no vector. This version will provide an empty vector for use if none is given. It will not be no vector at all. If you want that distinction, you should use boost's optional library, or a simple pointer, as references are not the right tool.
References cannot be NULL, your problem has nothing to do with operator overloading. If you want to be able to handle NULL as the default value, switch the parameter type from reference to pointer.
void obtain_priority_array( const std::vector<double>& weighting,
const ABC *priority_array = NULL)
{
if( priority_array == NULL ) {
// blah
} else {
// more blah
}
}
Another option is to use something like Boost.Optional to represent the optional parameter.
typedef boost::optional<ABC> maybe_ABC;
void obtain_priority_array( const std::vector<double>& weighting,
const maybe_ABC& priority_array = maybe_ABC() )
{
if( !priority_array ) {
// blah
} else {
// more blah
}
}
When you use = to create a reference, you're not calling operator= at all. You're initializing the reference.
Instead of using NULL you can create a static instance of the class to represent a null value.
static const ABC ABC_NULL;
void obtain_priority_array(const std::vector<double> &weighting, const ABC &priority_array=ABC_NULL)
{
if (&priority_array == &ABC_NULL) // the default was used
Of course it would be easier to just use a pointer instead of a reference.
Related
I have questions on where to even start on this problem.
The problem requires the following.
// We want to create a function that will add numbers together,
// when called in succession.
add(1)(2); // == 3
I have never seen functions be used in such a way, and I am currently at a loss of where to start. Furthermore, I tried to do some research on parameter chaining, but this is all I could find.
https://levelup.gitconnected.com/how-to-implement-method-chaining-in-c-3ec9f255972a
If you guys have any questions, I can edit my code or question. Any help is appreciated.
.... way and I am currently at a loss of where to start?
One way, is to start with an anonymous (unnamed) functor✱, which has operator(), that returns the reference to the this, as follows:
struct { // unnamed struct
int result{ 0 };
auto& operator()(const int val) noexcept
{
result += val;
return *this; // return the instance itself
}
// conversion operator, for converting struct to an int
operator int() { return result; }
} add; // instance of the unnamed struct
int main()
{
std::cout << add(1)(2); // prints: 3
}
See a live demo
✱Read more about the unnamed structs, functors and conversion operator here:
What are "anonymous structs" / "unnamed structs"?
What are C++ functors and their uses?
How do conversion operators work in C++?
The trick is to overload operator() and use a proxy object.
struct LhsAddProxy
{
int lhs_;
int operator()(int rhs) const { return lhs_ + rhs; }
};
LhsAddProxy add(int lhs) { return {lhs}; }
I'm trying to sort a vector of shared_ptrs to Food objects.
Food class is defined as:
class Food {
private:
// Human-readable description of the food, e.g. "all-purpose wheat
// flour". Must be non-empty.
std::string _description;
// Human-readable description of the amount of the food in one
// sample, e.g. "1 cup". Must be non-empty.
std::string _amount;
// Number of grams in one sample; must be non-negative.
int _amount_g;
// Energy, in units of kilocalories (commonly called "calories"), in
// one sample; must be non-negative.
int _kcal;
// Number of grams of protein in one sample; most be non-negative.
int _protein_g;
public:
Food(const std::string& description,
const std::string& amount,
int amount_g,
int kcal,
int protein_g)
: _description(description),
_amount(amount),
_amount_g(amount_g),
_kcal(kcal),
_protein_g(protein_g) {
assert(!description.empty());
assert(!amount.empty());
assert(amount_g >= 0);
assert(kcal >= 0);
assert(protein_g >= 0);
}
const std::string& description() const { return _description; }
const std::string& amount() const { return _amount; }
int amount_g() const { return _amount_g; }
int kcal() const { return _kcal; }
int protein_g() const { return _protein_g; }
};
using
// Alias for a vector of shared pointers to Food objects.
using FoodVector = std::vector<std::shared_ptr<Food>>;
My sorting algorithm is:
std::unique_ptr<FoodVector> greedy_max_protein(const FoodVector& foods,
int total_kcal)
{
std::unique_ptr<FoodVector> result(new FoodVector);
int result_cal = 0;
sort(foods.begin(), foods.end(), sortByProtein); //sorting error
...
The error is occuring with the sort function here ^^ and my sortByProtein function is:
bool sortByProtein(const std::shared_ptr<Food>&lhs, const std::shared_ptr<Food>&rhs)
{
return lhs->protein_g() > rhs->protein_g();
}
I keep getting the binary'='no operator found which takes a left hand operand type 'const std::shared_ptr' or there is no acceptable conversion. I've tried creating my own sort function but i get the same error. Do i need to overload operator= in my class ? If so how do i go about doing that? Any help would be greatly appreciated!
EDIT
fixed the issue by creating a new pointer:
FoodVector *sorted = new FoodVector(foods);
Thanks!
I chopped down and isolated the problem.
Before removing the "const" I got the same error you were getting.
But this compiles.
#include <iostream>
//:For: std::vector
#include <vector>
//:For: std::shared_ptr
#include <memory>
//:For: std::sort
#include<algorithm>
class Food{ /* SomeLogicHere */ };
typedef std::vector<std::shared_ptr<Food>> FoodVector;
bool operator==(
std::shared_ptr<Food> lhs,
std::shared_ptr<Food> rhs
){
return true; //TODO: Actual Comparison Logic
}
bool sortByProtein(
std::shared_ptr<Food> lhs,
std::shared_ptr<Food> rhs
) {
//:Dont Care about implementation.
//:Just want minimal example that
//:gets the error.
return false;
}
std::unique_ptr<FoodVector> greedy_max_protein(
FoodVector foods,
int total_kcal
){
sort(foods.begin(),foods.end(),sortByProtein);
}
int main()
{
std::cout<<"Hello World";
return 0;
}
The problem is in the function that is trying to sort
std::unique_ptr<FoodVector> greedy_max_protein(const FoodVector& foods,
int total_kcal)
{
std::unique_ptr<FoodVector> result(new FoodVector);
int result_cal = 0;
sort(foods.begin(), foods.end(), sortByProtein); //sorting error
std::sort() relies on the first two arguments being non-const iterators - i.e. that can be used to change the values they refer to. It is, after all, rather tough to sort a container if the elements cannot be reassigned.
foods is a const reference to a FoodVector (aka std::vector<std::shared_ptr<Food> >) so the begin() and end() functions are const, and return a type std::vector<std::shared_ptr<Food> >::const_iterator. That does not meet requirements of std::sort().
To fix the problem, either
remove the const qualifier from the first argument of the function greedy_max_protein(). Be aware this means that the function may change the elements of the passed FoodVector, and the caller will not be able to pass a const FoodVector;
Create a copy locally in the function and sort that. This is appropriate if the working of the function needs a sorted vector, but the caller requires that the passed vector remains unchanged.
I have a project that wants me to make a BigNum class in c++ (university project)
and it said to overload operator bracket for get and set
but the problem is if the set was invalid we should throw an exception the invalid is like
BigNum a;
a[i]=11;//it is invalid because its >9
in searching I found out how to make the set work
C++ : Overload bracket operators [] to get and set
but I didn't find out how to manage setting operation in c# you easily can manage the set value what is the equivalent of it in c++
to make it clear in C# we can say
public int this[int key]
{
set
{
if(value<0||value>9)throw new Exception();
SetValue(key,value);
}
}
New Answer
I have to rewrite my answer, my old answer is a disaster.
The check should happen during the assignment, when the right hand side (11) is available. So the operator which you need to overload is operator=. For overloading operator=, at least one of its operands must be an user defined type. In this case, the only choice is the left hand side.
The left hand side we have here is the expression a[i]. The type of this expression, a.k.a the return type of operator[], must be an user defined type, say BigNumberElement. Then we can declare an operator= for BigNumberElement and do the range check inside the body of operator=.
class BigNum {
public:
class BigNumberElement {
public:
BigNumberElement &operator=(int rhs) {
// TODO : range check
val_ = rhs;
return *this;
}
private:
int val_ = 0;
};
BigNumberElement &operator[](size_t index) {
return element_[index];
}
BigNumberElement element_[10];
};
OLD answer
You can define a wapper, say NumWapper, which wraps a reference of BigNum's element. The operator= of BigNum returns the wrapper by value.
a[i]=11;
is then something like NumWrapper x(...); x = 11. Now you can do those checks in the operator= of NumWrapper.
class BigNum {
public:
NumWrapper operator[](size_t index) {
return NumWrapper(array_[index]);
}
int operator[](size_t index) const {
return array_[index];
}
};
In the NumWrapper, overload some operators, such as:
class NumWrapper {
public:
NumWrapper(int &x) : ref_(x) {}
NumWrapper(const NumWrapper &other) : ref_(other.ref_) {}
NumWrapper &operator=(const NumWrapper &other);
int operator=(int x);
operator int();
private:
int &ref_;
};
You can also declare the NumWrapper's copy and move constructor as private, and make BigNum his friend, for preventing user code from copying your wrapper. Such code auto x = a[i] will not compile if you do so, while user code can still copy the wrapped value by auto x = static_cast<T>(a[i]) (kind of verbose though).
auto &x = a[i]; // not compiling
const auto &x = a[i]; // dangerous anyway, can't prevent.
Seems we are good.
These is also another approach: store the elements as a user defined class, say BigNumberElement. We now define the class BigNum as :
class BigNum {
// some code
private:
BigNumberElement array_[10];
}
We need to declare a whole set operators for BigNumberElement, such as comparison(can also be done through conversion), assignment, constructor etc. for making it easy to use.
auto x = a[i] will now get a copy of BigNumberElement, which is fine for most cases. Only assigning to it will sometimes throw an exception and introduce some run-time overhead. But we can still write auto x = static_cast<T>(a[i]) (still verbose though...). And as far as I can see, unexpected compile-time error messages is better than unexpected run-time exceptions.
We can also make BigNumberElement non-copyable/moveable... but then it would be the same as the first approach. (If any member functions returns BigNumberElement &, the unexpected run-time exceptions comes back.)
the following defines a type foo::setter which is returned from operator[] and overloads its operator= to assign a value, but throws if the value is not in the allowed range.
class foo
{
int data[10];
public:
void set(int index, int value)
{
if(value<0 || value>9)
throw std::runtime_error("foo::set(): value "+std::to_string(value)+" is not valid");
if(index<0 || index>9)
throw std::runtime_error("foo::set(): index "+std::to_string(index)+" is not valid");
data[index] = value;
}
struct setter {
foo &obj;
size_t index;
setter&operator=(int value)
{
obj.set(index,value);
return*this;
}
setter(foo&o, int i)
: obj(o), index(i) {}
};
int operator[](int index) const // getter
{ return data[index]; }
setter operator[](int index) // setter
{ return {*this,index}; }
};
If what you are trying to do is overload [] where you can input info like a dict or map like dict[key] = val. The answer is actually pretty simple:
lets say you want to load a std::string as the key, and std::vector as the value.
and lets say you have an unordered_map as your underlying structure that you're trying to pass info to
std::unordered_map<std::string, std::vector<double>> myMap;
Inside your own class, you have this definition:
class MyClass{
private:
std::unordered_map<std::string, std::vector<double>> myMap;
public:
std::vector<double>& operator [] (std::string key) {
return myMap[key];
}
}
Now, when you want to load your object, you can simply do this:
int main() {
std::vector<double> x;
x.push_back(10.0);
x.push_back(20.0);
x.push_back(30.0);
x.push_back(40.0);
MyClass myClass;
myClass["hello world"] = x;
double x = myClass["hello world"][0]; //returns 10.0
}
The overloaded [] returns a reference to where that vector is stored. So, when you call it the first time, it returns the address of where your vector will be stored after assigning it with = x. The second call returns the same address, now returning the vector you had input.
Could someone explain me what is going on in this example here?
They declare the following:
bool fncomp (int lhs, int rhs) {return lhs<rhs;}
And then use as:
bool(*fn_pt)(int,int) = fncomp;
std::set<int,bool(*)(int,int)> sixth (fn_pt)
While the example for the sort method in algorithm library here
can do like this:
bool myfunction (int i,int j) { return (i<j); }
std::sort (myvector.begin()+4, myvector.end(), myfunction);
I also didn't understand the following:
struct classcomp {
bool operator() (const int& lhs, const int& rhs) const
{return lhs<rhs;}
};
this keyword operator (not being followed by an operator as in a op. overload)... what is the meaning of it? Any operator applied there will have that behavior? And this const modifier... what is the effect caused by it?
I was trying to make a set of C-style string as follows:
typedef struct
{
char grid[7];
} wrap;
bool compare(wrap w1, wrap w2)
{
return strcmp(w1.grid, w2.grid) == -1;
}
set <wrap, compare> myset;
I thought I could create a set defining my sorting function in a similar as when I call sort from algorithm library... once it didn't compile I went to the documentation and saw this syntax that got me confused... Do I need to declare a pointer to a function as in the first example i pasted here?
struct classcomp {
bool operator() (const int& lhs, const int& rhs) const
{return lhs<rhs;}
};
Defines a functor by overloading the function call operator. To use a function you can do:
int main() {
std::set <wrap, bool (*)(wrap,wrap)> myset(compare);
return 0;
}
Another alternative is to define the operator as a part of the wrap class:
struct wrap {
char grid[7];
bool operator<(const wrap& rhs) const {
return strcmp(this->grid, rhs.grid) == -1;
}
};
int main() {
wrap a;
std::set <wrap> myset;
myset.insert(a);
return 0;
}
You're almost there... here's a "fixed" version of your code (see it run here at ideone.com):
#include <iostream>
#include <set>
#include <cstring>
using namespace std;
typedef struct
{
char grid[7];
} wrap;
bool compare(wrap w1, wrap w2) // more efficient: ...(const wrap& e1, const wrap# w2)
{
return strcmp(w1.grid, w2.grid) < 0;
}
set <wrap, bool(*)(wrap, wrap)> myset(compare);
int main() {
wrap w1 { "abcdef" };
wrap w2 { "ABCDEF" };
myset.insert(w1);
myset.insert(w2);
std::cout << myset.begin()->grid[0] << '\n';
}
"explain [to] me what is going on in this example"
Well, the crucial line is...
std::set<wrap, bool(*)(wrap, wrap)> myset(compare);
...which uses the second template parameter to specify the type of function that will perform comparisons, then uses the constructor argument to specify the function. The set object will store a pointer to the function, and invoke it when it needs to compare elements.
"the example for the sort method in algorithm library..."
std::sort in algorithm is great for e.g. vectors, which aren't automatically sorted as elements are inserted but can be sorted at any time. std::set though needs to maintain sorted order constantly, as the logic for inserting new elements, finding and erasing existing ones etc. all assumes the existing elements are always sorted. Consequently, you can't apply std::sort() to an existing std::set.
"this keyword operator (not being followed by an operator as in a op. overload)... what is the meaning of it? Any operator applied there will have that behavior? And this const modifier... what is the effect caused by it?
operator()(...) can be invoked on the object using the same notation used to call a function, e.g.:
classcomp my_classcomp;
if (my_classcomp(my_int1, my_int_2))
std::cout << "<\n";
As you can see, my_classcomp is "called" as if it were a function. The const modifier means that the code above works even if my_classcomp is defined as a const classcomp, because the comparison function does not need to modify any member variables of the classcomp object (if there were any data members).
You almost answered your question:
bool compare(wrap w1, wrap w2)
{
return strcmp(w1.grid, w2.grid) == -1;
}
struct wrap_comparer
{
bool operator()(const wrap& _Left, const wrap& _Right) const
{
return strcmp(_Left.grid, _Right.grid) == -1;
}
};
// declares pointer to function
bool(*fn_pt)(wrap,wrap) = compare;
// uses constructor with function pointer argument
std::set<wrap,bool(*)(wrap,wrap)> new_set(fn_pt);
// uses the function directly
std::set<wrap,bool(*)(wrap,wrap)> new_set2(compare);
// uses comparer
std::set<wrap, wrap_comparer> new_set3;
std::sort can use either a function pointer or a function object (http://www.cplusplus.com/reference/algorithm/sort/), as well as std::set constructor.
const modifier after function signature means that function can't modify object state and so can be called on a const object.
I have a class which has a member of type std:vector
private:
std::vector<int> myVector;
I have created Get method to access myVector
1. const std::vector<int> GetMyVector() const;
2. const void GetMyVector(std::vector<int>& vec) const;
The implementations are as follows respectively:
1. const std::vector<int> MyClass::GetMyVector() const
{
return myVector;
}
2. const void MyClass::GetMyVector(std::vector<int>& vec) const
{
vec = myVector;
}
Which one of the two Get methods is better and why?
I'd prefer option 3:
const std::vector<int>& MyClass::GetMyVector() const
{
return myVector;
}
Your option 1 returned a copy of myVector. This returns a const (so read-only) reference to the class member.
Why return the vector at all?
int MyClass::GetItem(const size_t index) const
{
return myVector[index];
}
First of all you are exposing your implementation when you return a private member of a class from a member function, which usually is bad design. Take a look at #JoachimPileborg's solution for an example of how to avoid this.
If you want to return a copy then you should return by value.
If you want to return a reference to an object then return by reference. However, bear in mind that when the object is destructed you will end up with a dangling reference, e.g.
class Foo {
public:
std::vector<int>& getVec() {
return myVec;
}
private:
std::vector<int> myVec;
};
int main() {
Foo* f = new Foo();
std::vector<int>& myRef = f->getVec();
delete f;
std::cout << myRef.size(); // The demons come! Dangling reference!
}
Because of this, it is often the right thing to return a copy instead of a reference.
If you are returning an object by copy then there is no any sense to declare it as const. So instead of
const std::vector<int> MyClass::GetMyVector() const
{
return myVector;
}
I would write
std::vector<int> MyClass::GetMyVector() const
{
return myVector;
}
The second declaration is worst than the first one because it only confuses users. It is not clear whether the corresponding data member of the class is assigned to the parameter or this method makes some changes of the parameter without assigning the corresponding data member to the parameter.
So considering suggested variants by you I would choise declaration
std::vector<int> MyClass::GetMyVector() const
{
return myVector;
}
As a rule of thumb always try to return const reference of a class member .
So use const std::vector<int> & MyClass::GetMyVector() const