How do I interpret this application of the safe bool idiom? [duplicate] - c++

I was pointed to the 'safe bool idiom', and after trying to decipher what is going on (the explanation supplied on the site was not sufficient enough to grant me understanding of why it works), I decided to try to take the following code apart and make an attempt at simplifying it as much as possible. The site supplied code below:
class Testable {
bool ok_;
typedef void (Testable::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
explicit Testable(bool b=true):ok_(b) {}
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
};
I decided to analyse the key basis of 'bool_type' given this seems to be what it's centred on. Given the following line:
typedef void (Testable::*bool_type)() const;
One can (not so easily, due to bracketing) deduce it's a typedef of a type of 'void Testable::*', of which bool_type represents. This can be further demonstrated by making the following modifications and function calls:
class Testable {
bool ok_;
typedef void (Testable::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
explicit Testable(bool b=true):ok_(b) {}
bool_type Test; //Added this
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
};
int main()
{
Testable Test;
int A = Test.Test; //Compiler will give a conversion error, telling us what type .Test is in the process
}
It allows us to see what type bool_type is:
error: cannot convert 'void (Testable::*)()const' to 'int' in initialization
Which shows it is indeed a type of 'void (Testable::*)'.
The issues crops up here:
If we modify the following function:
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
And turn it into:
operator void Testable::* () const //Same as bool_type, right?
{
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
It generates the following complaints:
error: expected identifier before '*' token
error: '< invalid operator >' declared as function returning a function
My questions are thus:
Why is it generating those complaints if 'void (Testable::*) is indeed the typedef for bool_type?
And
What is going on here?

Your reasoning goes wrong about here
operator void Testable::* () const //Same as bool_type, right?
This isn't correct. The type of bool_type is, as the compiler tells us in the error message:
'void (Testable::*)()const'
So, to replace it in the operator, you would need something like
operator (void (Testable::*)() const) () const
if that is ever possible! See why even the ugly typedef is an improvement?
In C++11 we also have the new construct explicit operator bool() to save us from this ugliness.

Related

How to fix discards qualifiers [-fpermissive] for cv::SVMParams?

I have a class ConfigFile that has a getter for the SVMParams member:
cv::SVMParams gerSVMParams()
{
return *m_mapConfig["SVMParams"];
}
The code is a little bit more complicated. m_mapConfig is a
std::map<std::string, std::unique_ptr< IConfigItem > >
And IConfigItem is a template class that looks like this for SVMParams:
template<> class ConfigItem< cv::SVMParams > : public IConfigItem
{
private:
cv::SVMParams m_value;
public:
ConfigItem(const cv::SVMParams& valueIn) : m_value(valueIn) {}
operator cv::SVMParams() const
{
return m_value;
}
};
My problem is when I am trying to auto train the SVM classifier:
classifier.train_auto(trainingData, classes, cv::Mat(), cv::Mat(), configFileIn.getSVMParams());
I am getting an error of kind:
error: passing ‘const ConfigFile’ as ‘this’ argument of ‘cv::SVMParams ConfigFile::getSVMParams()’ discards qualifiers [-fpermissive]
Any suggestions of what I am doing wrong? Or is there a small bug because because the train_auto functions has no const in front of the SVMParams parameter. Or is it modifying it?
Make your function const:
cv::SVMParams gerSVMParams() const
// ^^^^^
The error is you are calling a non-const method on a const object, which the compiler rejects as being potentially unsafe. That said, your implementation is inherently non-const too since you might be inserting an object into your map, so just adding the const won't help.
What you probably want to do is:
cv::SVMParams gerSVMParams() const
// ^^^^^
{
auto it = m_mapConfig.find("SVMParams");
if (it != m_mapConfig.end()) {
return *(*it);
}
else {
return {}; // maybe?
}
}
Found the problem: I was calling the function in which I was calling the getSVMParams() with const ConfigFile&; and that was not allowed by the shared_ptr I used in the map.
Thanks all, anyway!

compilation error: overloading operator()

VisualStudio 2008 (VC++ 9)
Problem with overloading operator()
Hello community!
It seems that overloaded version of operator() must all differ in their argument list, independly of the return type.
I have the following case:
class Sha256{
public:
QVector<quint32> operator()(QString const& data);
QByteArray operator()(QByteArray const& data);
QVector<quint32> operator()(QByteArray const& data); // this is line 168
...
}
Last declaration leads to following compilation error:
.\sha256.cpp(168) : error C2556: 'QVector Sha256::operator ()(const QByteArray &)' : overloaded function differs only by return type from 'QByteArray Sha256::operator ()(const QByteArray &)'
with
[
T=uint
]
On the other side, following declarations are working:
class Sha256{
public:
QVector<quint32> operator()(QString const& data);
QByteArray operator()(QByteArray const& data);
...
}
because they have different arguments.
One way would be to add in the first case an additional argument like
QByteArray<quint32> operator()(QByteArray const& data, bool getByteArray)
but this is embarassing, not intuitive and also not clean (return type would be a QByteArray, independly of the value of getByteArray, even in case of false!).
Another way could be to use a template function like
template<class T> T operator()(QByteArray const& ba)
template<class T> T operator()(QString const& str)
but T could only be of a few 'supported' type (QByteArray and QVector), therefore user could run into trouble if using wrong T Type. This version seems to be error prone.
So my questions are:
1. Why is the return type of function objects not taken into account in the signature to distinguish between different flavors of the function like in 'classical' functions?
2. Is there a better way around than adding an additional dummy argument?
Thank you for your valuable time.
Alain
Return type is never used for overload resolution. In fact, you can't even declare two functions that differ only in return type. In my opinion, adding this feature would be complicated and not that helpful. Is it necessary to use the function call operator? You could just use a named member function, and then give them different names. Another option would be to use a member template, but even then you would need to explicitly give the return type as a template argument, and the syntax would be ugly if done on the function call operator.
The comment from Kerrek SB suggests a workaround by leveraging conversion operators, if you are okay with something that is complex on the inside, but simpler on the outside.
#include <iostream>
struct A {};
struct B {};
A fooA_impl(const char *) {
std::cerr << "A impl" << std::endl;
return A();
}
B fooB_impl(const char *) {
std::cerr << "B impl" << std::endl;
return B();
}
class Helper {
public:
operator A() { return fooA_impl(p); }
operator B() { return fooB_impl(p); }
private:
friend Helper foo(const char *p);
Helper(const char *p_) : p(p_) {}
const char *const p;
};
Helper foo(const char *p) {
return Helper(p);
}
int
main() {
A a(foo("hello"));
B b(foo("hello"));
}
You can't use overload by return type. One thing you can do is to add the return type as a tag parameter when overloading operator():
QByteArray operator()(QByteArray const& data, const QByteArray& tag );
QVector<quint32> operator()(QByteArray const& data, const QVector<quint32>& tag);
The below is how you call these function:(assume both types have default constructors).
(data, QByteArray());
(data, QVector<quint32>());

Compilation error about operator reloading using boost::variant

I'am trying to learn boost.variant. However, the code which I copied from a book won't pass the compilation:
class var_print : public boost::static_visitor<void>
{
public:
template<typename T>
void operator()(T &i) {
i *= 2;
cout<<i<<endl;
}
};
Here is how I tried to use it.
typedef boost::variant<int,double,string> var_t;
var_t v(1); //v->int
boost::apply_visitor(var_print(),v);
The compiler generates the following error:
ERROR:no match for 'operator*=' in 'i *= 2'
That puzzles me,since template function will determine the type of parameter whenever it's called and int should defined the operator *=.
You need to have a separate operator() for std::string& since no operator *= is defined for std::string.
In addition, your operator must be marked const since you are passing a temporar visitor instance to apply_visitor.

How does the safe bool idiom bool_type (and the safe bool idiom) work?

I was pointed to the 'safe bool idiom', and after trying to decipher what is going on (the explanation supplied on the site was not sufficient enough to grant me understanding of why it works), I decided to try to take the following code apart and make an attempt at simplifying it as much as possible. The site supplied code below:
class Testable {
bool ok_;
typedef void (Testable::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
explicit Testable(bool b=true):ok_(b) {}
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
};
I decided to analyse the key basis of 'bool_type' given this seems to be what it's centred on. Given the following line:
typedef void (Testable::*bool_type)() const;
One can (not so easily, due to bracketing) deduce it's a typedef of a type of 'void Testable::*', of which bool_type represents. This can be further demonstrated by making the following modifications and function calls:
class Testable {
bool ok_;
typedef void (Testable::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
explicit Testable(bool b=true):ok_(b) {}
bool_type Test; //Added this
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
};
int main()
{
Testable Test;
int A = Test.Test; //Compiler will give a conversion error, telling us what type .Test is in the process
}
It allows us to see what type bool_type is:
error: cannot convert 'void (Testable::*)()const' to 'int' in initialization
Which shows it is indeed a type of 'void (Testable::*)'.
The issues crops up here:
If we modify the following function:
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
And turn it into:
operator void Testable::* () const //Same as bool_type, right?
{
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
It generates the following complaints:
error: expected identifier before '*' token
error: '< invalid operator >' declared as function returning a function
My questions are thus:
Why is it generating those complaints if 'void (Testable::*) is indeed the typedef for bool_type?
And
What is going on here?
Your reasoning goes wrong about here
operator void Testable::* () const //Same as bool_type, right?
This isn't correct. The type of bool_type is, as the compiler tells us in the error message:
'void (Testable::*)()const'
So, to replace it in the operator, you would need something like
operator (void (Testable::*)() const) () const
if that is ever possible! See why even the ugly typedef is an improvement?
In C++11 we also have the new construct explicit operator bool() to save us from this ugliness.

No legal conversion to 'this' pointer

Please take a look at this code and run it:
I'm getting very strange error:
Error 1 error C2663: 'Allocator::allocate_help' : 2 overloads have no legal conversion for 'this' pointer
template<class FailureSignal>
class Allocator
{
private:
template<class Exception,class Argument>
void allocate_help(const Argument& arg,Int2Type<true>)
{
}
template<class Exception,class Argument>
std::nullptr_t allocate_help(const Argument& arg,Int2Type<false>)
{
return nullptr;
}
public:
template<class T>
void Allocate(signed long int nObjects,T** ptr = 0)const
{
allocate_help<std::bad_alloc>(1,Int2Type<true>());
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Allocator<int> all;
all.Allocate<int>(1);
return 0;
}
I absolutely do not understand this err msg. Hope someone can help me with this. Thank you.
I noticed Allocate is declared const but allocate_help is not - could that be related to the issue?
I had the same error which was also caused by const but in a bit different way.
I have two virtual functions (overloads), one was const and the other was not. This was causing the problem. Turns out if you want to overload a function, they both need to match if they are const or not.
virtual void value() const = 0;
virtual void value(MyStruct & struct) = 0;
The above code will cause this error. The fix is to change declaration of 2nd to:
virtual void value(MyStruct & struct) const = 0;
I had this problem, when i tried to change member data in a const declared method.
As we all know, const methods are supposed not to change member data.
The compiler gcc/clang doesn't return good error message.
It successfully compiled after removing const specifier from
void I_am_a_const_method_but_trying_to_modify_member() const{
amap.emplace(std::make_tuple(1, 1, "a"), 1);
}
compiler explorer link