If you notice in the following functions they both have the same for loop that searches for a integer location. Pop() compiles but I get an error for top() having to do with the const qualifiers. The heap class inherits from eecs281heap which stores a functor Comp compare where Comp is the typename. The instructor told us the only way to access the functor is through this->() so i'm just lookin for some guidance here. Thanks
error: passing ‘const larger’ as ‘this’ argument of ‘bool larger::operator()(int, int)’ discards qualifiers
This happens after running the following in int main. Through testing I already know the constructor works properly.
vector <int> data={10,2,13};
poorman_heap<int,larger> y(data.begin(),data.end());
template<typename TYPE, typename COMP>
void poorman_heap<TYPE, COMP>::pop() {
int location=0;
for(int i=1;i<data.size();i++){
if(this->compare(data.at(i),data.at(location))){
location=i;
}
}
data.erase(data.begin()+location);
return;
}
template<typename TYPE, typename COMP>
const TYPE& poorman_heap<TYPE, COMP>::top() const {
int location=0;
for(int i=1;i<data.size();i++){
if(this->compare(data.at(i),data.at(location))){
location=i;
}
}
return data.at(location);
}
P.S. greater is
struct greater{
bool operator()(int x,int y){
return x>y;
}
}
Make the call operator of greater a const operator:
struct greater
{
bool operator()(int x,int y) const
{
return x>y;
}
}
The same applies to whatever this->compare resolves to. It needs to be const.
It doesn't make much sense for a comparator to be non-const.
It looks like the problem is that the compare member has operator() declared as a non-const function. Since it sounds like you don't have the ability to change that, you might be able to get the behavior that you want by declaring it as a mutable member in poorman_heap.
The mutable keyword lets you distinguish between an object being "physically const" (meaning the actual bytes don't change and being "logically const" (meaning the bytes might change but the value of the object isn't different in a fundamental sense). Basically it means that something "doesn't count" for the purposes of const-ness. The classic example in my mind is lazy initialization - you want to declare the get_value() function on a class const, but you also don't want to waste time computing the value if no one uses it, so you declare the value mutable and now you're allowed to calculate it and assign to it inside get_value() even though it is a const member function.
Related
I'm new to cC++. I hope the code snippet explains well enough what I'm trying to achieve. I want a global and a element function for overloading of the < operator. In the element function the return type is bool and in the global function it is the respective type. Is this code possible to realize? (Not working right now?)
class Foo{
//...
//element function:
bool operator<(const Foo& otherFoo){//implementation}
}
//global function:
Foo& operator<(const Foo& foo1, const Foo& f2)
{
if (f1.operator<(f2))
return f1;
else;
return f2;
}
Is this code possible to realize?
Yes. But you really, really, really should not do it! operator< has a very concise meaning: Is the left hand side "less" (for some definition of "less") than the right hand side?
Returning the object which is actually "less" is also a reasonable function, but it should be named accordingly! Call it lesser_of or something like that.
Not working right now?
You did not include any useful error description in your question, but I highly suspect that the issue here is const correctness. You're accepting a reference to a const qualified Foo and try to call its member function operator< which is not const qualified. The simple fix: Add a const to the member function:
// member function: vvvvv
bool operator<(const Foo& otherFoo) const {
// implementation ^^^^^
}
The supposed free (= non-member) function (which should really be called with a reasonable name, I chose lesser_of) can be implemented for all types with a corresponding member function, using a template:
template<typename L, typename R>
typename std::common_type<L,R>::type lesser_of(L&& left, R&& right) {
using std::forward;
// Could also use operator<(forward<L>(left), forward<R>(right)), but
// this breaks when there's both a member function and a free
// function available.
if (left.operator<(forward<R>(right))) {
return forward<L>(left);
} else {
return forward<R>(right);
}
}
Note that I have no idea whether the forwarding makes any sense, nor am I sure if this could lead to dangling references.
Going a bit further, there's one kind of usage that I would consider "only just ok" if you really insist on returning "more" than a bool from operator<: In Common Lisp this is called "generalized boolean", and basically means that anything except a special nil value is considered to be "truthy". You could "port" that to C++ and use std::optional (C++17!) to convey that meaning:
template<typename L, typename R>
std::experimental::optional<L> operator<(L&& left, R&& right) {
if (left.operator<(std::forward<R>(right))) {
return std::forward<L>(left);
} else {
return std::experimental::nullopt_t{};
}
}
This returns the left operand wrapped in a std::optional if indeed it is "less" than the right. The result can be checked for in e.g. an if (or similar "special context") because it has a (explicit) conversion member function to bool. Thus returning std::optional instead of bool won't break code that uses the comparison only where contextual conversions can be applied. The returned value can be access by dereferencing or for example the value member function.
Of course this does not allow code like Foo c = a < b;, but you could instead use Foo c = (a < b).value_or(b);.
I have simple data structure called array (similar to std::array). array class have method called all(). Here are method declarations:
const range<const_type_pointer> all() const;
range<type_point> all();
range is class template, which is constructed by two iterators. Here is simplified version of range class declaration:
template <typename Iterator>
class range {
typedef typename iterator_traits<Iterator>::type_value type_value;
typedef typename iterator_traits<Iterator>::type_reference type_reference;
typedef typename iterator_traits<Iterator>::type_pointer;
range(Iterator begin, Iterator end);
// methods & algorithms
// data members
mutable Iterator _begin;
mutable Iterator _end;
};
So basically, if I call method all on const array object, it should call const overload of method and return const range. Now, in my algorithms section, I have simple algorithm with following signature:
template <typename UnaryFunction>
range forEach(UnaryFunction function);
Then I tried following test:
void test1(const array<int, 10>& array)
{
auto r = array.all();
r.forEach([](int i) { std::cout << i << " "; });
}
And second one:
void test2(const array<int, 10>& array)
{
auto r = array.all();
r.forEach([](int& i) { ++i; });
}
In first case, where I was just printing variable i, compiler did not complained, even though I called non-const range method on const range object. In second case, compiler complained. Is this behaviour standard confornant?
As a compiler, I am using MSVS compiler.
First. Sice you are returning by value, it doesn't really make any difference if you are returning const range or range.
Second. auto r = array.all(); creates a copy of whatever was returned by all. Your r is a non-const object, and non-const forEach is used. But since the iterator is const in the second version, you can't modify the iterable.
auto works just like template argument deduction, which means that it drops top-level references and top-level const & volatile qualifiers. In other words, your r is of type range<const_pointer_type> in both cases.
Returning a const-qualified object should only be done in very special circumstances when you understand all details of its behaviour and really know that you want them.
Normally, you should just return objects without cv-qualifiers. It will play nicer with move semantics, and will not lead to incorrect expectations.
Consider the following code snippet:
class MyClass {
int x;
public:
MyClass(int val) : x(val) {}
const int& get() const {return x;}
};
void print (const MyClass& arg) {
cout << arg.get() << '\n';
}
int main() {
MyClass foo (10);
print(foo);
return 0;
}
Whether I add a const modifier before the instatiatation of MyClass or not, the program successfully compiles (without any warning) and prints 10. Why can print accept a non-const argument? Or, in other words, what is the function of the const modifier in the function parameter? Why can the formal and actual parameters of a function have different types (or modifiers)?
I have tried both GCC (4.8.2) and Clang (3.4) with -Wall -std=c++11 on Ubuntu 14.04, and the results were the same (no errors/warnings). I have also searched "c++ const object function" but didn't get anything that looked promising.
This is completely sane and normal. The object is treated as const within your function; it does not matter that it was not originally created to be immutable.
Of course, the opposite is not true!
void foo(T& rarr);
int main()
{
const T lolwut;
foo(lolwut); // oops
}
const forbids the body of the function from modifying the parameter variable. Both ways compile because you didn't attempt to modify it.
You can overload const and non-const reference parameters, and the const overload will only be chosen if the argument is really const (or a type conversion results in a temporary being passed). (For non-reference parameters, const seldom makes sense and such overloads may not even be defined.)
All that const does in this case is to prevent modification of parameter variable (and in the case of classes, prevent the calling of functions that are not labelled as const). MyClass may be trivially cast to const MyClass because there should be nothing that you can do to a const MyClass that you can't do to a non-const one. The reverse is not true, of course.
(I say "should" above, because it is of course possible to completely subvert const semantics under C++ if you wanted to, so the presence of const in a function prototype is really only a hopeful hint rather than a cast-iron compiler-enforced guarantee. But no sensible programmer should be breaking things like that!)
I have a template class, called OneCell, here the definition:
template <class T>
class OneCell
{
.....
}
I have a cast operator from OneCell to T, here
operator T() const
{
getterCount++;
return value;
}
As you see, I want to increment variable in this method, but i get an error because the keyword const.
On the other hand, if I remove this keyword, the casting doesn't work at all.
What can I do?
Thank you, and sorry about my poor English.
Actually operator T() const is a const-member function, inside which this pointer refers to a const object, which in turns makes the getterCount const as well.
The solution is to declare getterCount as mutable, as shown below:
mutable size_t getterCount;
Now getterCount can be incremented in const member function, which also means, it can be incremented even if the object is const:
void f(OneCell const & cell)
{
//incrementing getterCount!
++cell.getterCount; //ok, even though cell is const!
}
As you see, I want to increment variable in this method, but i get an error because the keyword const. On the other hand, if I remove this keyword, the casting doesn't work at all.
It will work, but only on mutable instances of OneCell.
What can I do?
Go mutable, assuming that you change the bitwise constness but not the logical constness.
mutable int getterCount;
I got a simple C++ struct as follows:
// Functor for peak to decreasing intensity sorting
struct cmp_decr_int2
{
bool operator() (peak2 a, peak2 b)
{
return a.int2 > b.int2;
}
};
is there an overload of the operator in this sample?
Yes. operator() is called the "function call" operator, and allows an object to be usable as if it were a function. Such a class is called a "functor".
A common pattern is to make functors that compare two things for equality or relations, for use in anything requiring a comparison predicate. (This one could be usable in an std::map, for example. It would have a member likecmp_decr_int2 compare; and then it could compare the relation between two things with: if (compare(x, y)) /* x is less than y, by some metric */)
This particular struct orders two peak2's by comparing their int2 members. It could be better written as:
struct cmp_decr_int2
{
// note const! vvvvv
bool operator() (peak2 a, peak2 b) const
{
return a.int2 > b.int2;
}
};
The function should be const because it does not need to change any members (there are none to change.) const-correctness is important.*
In many cases these functors are used in contexts where the arguments themselves are const, so you should either take the arguments by value as in the example or by constant reference.
You should prefer to pass types by const-reference over by-value, except when that type is fundamental (float, unsigned int, double, etc.) or smaller than a void*. In most cases, then, you will pass by const-reference:
struct cmp_decr_int2
{
// note const&: vvvvv v vvvvv v vvvvv
bool operator() (const peak2 & a, const peak2 & b) const
{
return a.int2 > b.int2;
}
};
*If this were used as a predicate in a std::map, for example, without const the map wouldn't be able to compare two things while within a const function.
Structs in C++ are just classes with a default accessor of public instead of private. So yes, that would have a function overload.
in c++ a struct is in every way like a class, except that the default parameter access is public: rather than private:. It is a common practice to use struct instead of class when the scope of the defined type's use is very narrow, such as in the example of a simple functor.
What this example does is emulate the appearance of a function pointer without the fragility of possibly being null.
The operator() member here overloads function calling. when you try to do something like:
cmp_decr_int2 foo;
foo(peek2(), peek2());
that overload member gets called.
#include <iostream>
using namespace std;
struct cmp_decr_int2
{
bool operator() (int a, int b)
{
return a > b;
}
bool operator() (int i)
{
return i > 0;
}
};
int main()
{
cmp_decr_int2 a;
cout << a(1, 2) << endl;
cout << a(1) << endl;
}
Yep, sure can overload the function! This worked perfectly for me.
$13.5.4 states-
operator() shall be a non-static member function with an arbitrary number of parameters. It can have default arguments. It implements the function call syntax postfix-expression ( expression-listopt ) where the postfix-expression evaluates to a class object and the possibly empty expression-list matches the parameter list of an operator() member function of the class. Thus, a call x(arg1,...) is interpreted as x.operator()(arg1, ...) for a class object x of type T if T::operator()(T1, T2, T3) exists and if the operator is selected as the best match function by the overload resolution mechanism (13.3.3).
Therefore, the struct 'cmp_decr_int2' has definitely overloaded operator().
Note that this is also the only operator in C++ that can take variable number of arguments.