I'm getting a compilation error when I call the constructor of TestComp, which is designed as follows:
template <typename R>
class IComparable
{
public:
virtual bool Equals(const R & rhs) const = 0;
};
class TestComp : IComparable<char*>
{
public:
std::string x;
TestComp(std::string & a)
{
x = a;
}
virtual bool Equals(const char* & a) const
{
return x == std::string(a);
}
};
Error:
error C2259: 'TestComp2' : cannot instantiate abstract class due to following members:'bool IComparable<R>::Equals(const R &) const' : is abstract with [ R=char * ]
which I can't understand as I'm defining TestComp::Equals with what appears to be the same signature as IComparable::Equals.
One thing I've noticed when trying various workarounds is that if I make both functions 'Equals(R & rhs) const' removing the const from the parameter then I no longer get this error.
Can someone help me understand this behavior?
The signature of the derived method is incorrect. It should be
virtual bool Equals(char* const& a) const
Note that the const is "applied" to the type before the next closest * and & and &&, i.e.,
const char* &, which is equivalent to char const* &, means a reference to a const-pointer to char.
char* const& means a const-reference to a pointer to char.
const R&, which is equivalent to R const&, means a const-reference to R.
const R &
That is a const reference (or, pedantically, a reference to a const object).
const char* & a
That is a non-const reference (to a pointer to a const object); therefore, it doesn't override the function taking a const reference. You need a const reference to a non-const pointer:
char * const & a
The const always qualifies the thing before it, unless it comes at the start, in which case it qualifies the first thing. Some people suggest making a habit of consistently putting it after the thing it qualifies, i.e. R const & rather than const R &, to slightly reduce the opportunity for confusion.
Related
Maybe it is a trivial question, but I can't actually find an answer. If I have a class like in the example below do I need to provide both const and non-const version of functions like in case of std::vector? Would a single constexpr function do the same job?
template <typename Type>
class Collection
{
public:
virtual ~Collection() {}
virtual size_t size() noexcept = 0;
virtual size_t size() const noexcept = 0;
virtual Type operator[](size_t index) noexcept = 0;
virtual Type operator[](size_t index) const noexcept = 0;
};
It depends. If the non-const version would do the same thing as the const version, then no. If someone has a non-const instance of a class, they can still call const methods.
There are some methods that may need both. Consider your indexing operator. If it instead returned a reference to the type, you would probably want both:
virtual Type& operator[](size_t index) noexcept = 0;
virtual const Type& operator[](size_t index) const noexcept = 0;
The methods aren't exactly the same because they are returning different types. This would mean that if someone has a const instance of your type, they could not get a mutable reference to an element.
A single constexpr function could do the job as long as the potential const/non-const implementations would be the same.
So I defined a class on C++ that inherits from a vector of pointers:
class SuperBinList : public std::vector<SuperBin*>{
public:
SuperBinList();
SuperBinList(const std::vector<SuperBin*>& superBinList);
virtual ~SuperBinList();
SuperBinList& operator += (SuperBin* superBin);
SuperBinList& operator += (const SuperBinList& superBin);
void sortByZbi(const double sys);
void sortBySoverB() const;
};
The SuperBin class itself is defined as:
class SuperBin{
public:
SuperBin(const VI index, const double nSig, const double nBkg, const VS mPerpLabel, const VS rIsrLabel, const VS visLabel);
virtual ~SuperBin();
VI getIndex();
double getNsig();
double getNbkg();
double getSoverB();
double getBinZbi(const double sys);
VS getMperpLabel();
VS getRisrLabel();
VS getVisLabel();
SuperBin* tryMerge(SuperBin* superBin, double sys);
private:
VI index_;
double nSig_;
double nBkg_;
double sOverB_;
VS mPerpLabel_;
VS rIsrLabel_;
VS visLabel_;
};
Now the problem I'm having is that I want the SuperBinList class to be able to sort itself in descending order in terms of any of the (double type) members of the SuperBin class (such as sOverB). For this I tried the following method using a lambda function:
void SuperBinList::sortBySoverB() const{
std::sort(this->begin(), this->end(), [](const SuperBin* lhs, const SuperBin* rhs){
return lhs->getSoverB() < rhs->getSoverB();});
}
The top error I'm getting is:
error: passing 'const SuperBin' as 'this' argument discards qualifiers [-fpermissive]
return lhs->getSoverB() < rhs->getSoverB();});
Which, as I understood from similar threads, has to do with the const specifiers. However, I'm still not sure what it is that I am doing wrong. Any help would be greatly appreciated. Please pardon my ignorance as I am a physics PhD and not a computer scientist.
You have your SuperBinList::sortBySoverB() function defined as const, which means it is not allowed to modify SuperBinList, and
this will have the type const SuperBinList *, rather than SuperBinList *
Similarly, your lambda is define with const pointers const SuperBin* lhs, meaning you can only call const functions.
Change your function definitions to void SuperBinList::sortBySoverB() {} and double getSoverB() const {}, and it should compile. (Generally member functions should be marked const if they are read-only operations like getters).
A class definition in the vein of,
class T {
public:
Mat D;
void operator()(double &p, const int * pos) const {
D.at<double>(pos[0]*2 + 1, 1) = p;
}
T(Mat D);
};
results in a compilation error, 'cv::Mat::at': you cannot assign to a variable that is const. The constructor simply assigns D as the argument.
Moving D to a global scope fixes the error but that is of course not preferred. This leads me to two questions:
What is the source of the error and can it be resolved?
Is there a better way to pass a variable into the scope of a Functor?
For the second point it should be noted for clarity that the functor will be used inside Mat::forEach<double>, so passing additional variables as arguments is not an option.
void operator()(double &p, const int * pos) const
is a const function. That means inside the function body, all class members are treated as if they were declared as const. Since you want to mutate D you have a few options, you can remove the const, you can declare D as mutable so it can be modified, or you could make D a reference member like
class T {
public:
Mat& D;
void operator()(double &p, const int * pos) const {
D.at<double>(pos[0]*2 + 1, 1) = p;
}
T(Mat& D) : D(D);
};
This works because the reference is marked as const (which means nothing since references can't be reassigned), not what it refers to.
I want to define some generic pointer (? but not a void pointer) using this code:
class A
{
template<typename T>
using ptr = T*;
using ubyte = uint8_t;
public:
const ptr<ubyte>
getColor1() const {
return &colors[0];
}
const ubyte*
getColor2() const {
return &colors[0];
}
private:
ubyte colors[4];
};
However, the getColor1() won't compile.
What's the difference between this two functions ?
gcc says:
error: invalid conversion from 'const ubyte* {aka const unsigned char*}' to 'A::ptr<unsigned char> {aka unsigned char*}' [-fpermissive]|
Update:
The deleted answer says I could do this:
//option 1
template<typename T>
using const_ptr = const T*;
or
//option 2
const ptr<ubyte>
getColor() //remove cv-qualifier
{
return &colors[0];
}
From option1,
It constructs now to const const, what does const const means?
From option2,
Why just removing cv-qualifier makes this compile?
const ptr<ubyte> is the same as const (ubyte *) which is not the same as const ubyte (*). You are trying to return a const pointer to a non-const char, which the compiler won't allow because you've declared the function itself const; all members become const because of that. The compiler won't automatically cast const to non-const without a const_cast.
To make the difference clearer, the first is a const pointer to a non-const char and the second is a non-const pointer to a const char. The first allows the pointed-to characters to change, even though the pointer itself can't change. Since the function was marked as const it can't return anything that would allow its members to be modified.
The best way to fix it:
ptr<const ubyte>
getColor1() const {
return &colors[0];
}
Because of the syntax of your ptr template, const ptr<ubyte> first makes it a ubyte*, then applies the const, resulting in a ubyte * const, a constant pointer to an ubyte.
In order to return a pointer to a const ubyte, you need to feed a const ubyte into your pointer template, so constness is applied first:
ptr<const ubyte>
1) "what does const const means?"
const T* const pT = new T;
Means const pointer pT - you cannot assign pT to another object;
to a const object of type T - you cannot change the object which is pointed by pT.
2) "Why just removing cv-qualifier makes this compile?"
getColor1()
method without const modifier can modify the object. It now returns A::ubyte* which can be converted to a const type such as declared as return type: A::ubyte* const (const ptr< ubyte > )
I am not sure about the effect of const modifier and reference in the template argument of std::function. For example, in the following codes, should I use std::function<bool(std::string, std::string)> or std::function<bool(const std::string&, const std::string&)> as the base class ? I tested both in GCC 4.4, however, there was no difference. Thanks in advance.
#include <iostream>
#include <functional>
#include <string>
//struct FLess : public std::function<bool(std::string, std::string)>
struct FLess : public std::function<bool(const std::string&, const std::string&)>
{
bool operator () (const std::string& s1, const std::string& s2) const
{
return s1 < s2;
}
};
int main(int argc, char* argv[])
{
FLess f;
std::string a = "a";
std::string b = "b";
std::cerr << f(a, b) << std::endl;
return 0;
}
You are not supposed to inherit from std::function.
Rather you use to abstract the underlying kind of function object like this:
void DoSomething(function<void(const string&, const string&) myF)
{
string s1, s2;
myF(s1, s2);
}
// usage:
DoSomething(bind(otheFunc, ....));
DoSomething([](const string& s1, const string& s2) { ... });
struct Func
{
operator()(const string& s1, const string& s2)
{ ... }
}
Func f;
DoSomething(f);
Now to answer your question, if you use const string& you are asking the compiler not to copy the object and to forbid modifications. That choice depends on the meaning you are giving to your parameters.
For small types like numbers and small struct, pass by copy.
Unless you want to perform very advanced copy/move optimizations, you'd better always use const& for large types. I'd consider string a large type, unless you are sure that it will never grow.
It boils down to compatibility between the function object's parameter types and those of the callable entity it is referring to, if the function's parameter types can be converted to the callable entities parameter types or not:
void foo(double x, double y);
void bar(const double& x, const double& y);
void fooBar(double& x, double& y);
std::function<void(const double&, const double&)> f;
f = &foo; // OK
f = &bar; // OK
f = &fooBar; // Error on GCC 4.7. Cannot instantiate a double& from const double.
Interestingly, an std::function with void return type is compatible with callable entities with any return type:
int fooBarFoo(const double& x, const double& y);
f = &fooBarFoo; // OK
So in your case, where you are comparing passing by const reference as opposed to passing by value, I think there is no observable difference.
Passing a reference to a const object avoids making a copy of the object just to pass to the function. In your case (a tiny string) it probably doesn't make enough difference to notice.
If you were dealing with a string of (say) several megabytes, passing by reference to const would avoid allocating space for (and copying) all that data.
At the same time, most compilers internally implement references pretty much like pointers. This can lead to slower execution because of an extra level of indirection. For small items (char, int, probably long) you usually prefer to pass by value. For larger items (potentially long strings, matrices, etc.) you usually prefer to pass by reference. If in doubt, usually pass by reference -- the penalty for being wrong in this direction is generally fairly small.