By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,264 Members | 1,763 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,264 IT Pros & Developers. It's quick & easy.

Safe bool idiom - protected function not accessible

P: n/a
In an article on the safe bool idiom
(http://www.artima.com/cppsource/safeboolP.html), Bjorn Karlsson gives
the following code (slightly modified):

class safe_bool_base {
protected:
typedef void (safe_bool_base::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}

safe_bool_base() {}
safe_bool_base(const safe_bool_base&) {}
safe_bool_base& operator=(const safe_bool_base&) {return *this;}
~safe_bool_base() {}
};

template <typename T=voidclass safe_bool : public safe_bool_base {
public:
operator bool_type() const {
return (static_cast<const T*>(this))->boolean_test()
? &safe_bool_base::this_type_does_not_support_compar isons : 0;
}
protected:
~safe_bool() {}
};
template<class safe_bool<void: public safe_bool_base {
public:
operator bool_type() const {
return boolean_test()==true ?
&safe_bool_base::this_type_does_not_support_compar isons //Error!
: 0;
}
protected:
virtual bool boolean_test() const=0;
virtual ~safe_bool() {}
};
template <typename T, typename U>
void operator==(const safe_bool<T>& lhs,const safe_bool<U>& rhs) {
lhs.this_type_does_not_support_comparisons();
return;
}

template <typename T,typename U>
void operator!=(const safe_bool<T>& lhs,const safe_bool<U>& rhs) {
lhs.this_type_does_not_support_comparisons();
return;
}

class Testable_with_virtual : public safe_bool<{
protected:
bool boolean_test() const {
return false;
}
};

class Testable_without_virtual :
public safe_bool <Testable_without_virtual{
public:
bool boolean_test() const {
return true;
}
};

This does not compile with VC8, VC7, or Comeau, but it does with EDG,
GNU, and VC6 (slightly modified further to account for
non-conformancies with void template args). The error occurs on the
line indicated by "Error!" and on Comeau reads:

"ComeauTest.c", line 26: error: protected function
"safe_bool_base::this_type_does_not_support_compar isons" (declared at
line 4) is not accessible through a "safe_bool_base" pointer or object
&safe_bool_base::this_type_does_not_support_compar isons //Error!
^

Notice that only the class template's specialization has a problem. Is
Comeau right as usual?

Cheers! --M

Dec 14 '06 #1
Share this Question
Share on Google+
14 Replies


P: n/a
mlimber wrote:
In an article on the safe bool idiom
(http://www.artima.com/cppsource/safeboolP.html), Bjorn Karlsson gives
the following code (slightly modified):

class safe_bool_base {
protected:
typedef void (safe_bool_base::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}

safe_bool_base() {}
safe_bool_base(const safe_bool_base&) {}
safe_bool_base& operator=(const safe_bool_base&) {return *this;}
~safe_bool_base() {}
};

template <typename T=voidclass safe_bool : public safe_bool_base {
public:
operator bool_type() const {
return (static_cast<const T*>(this))->boolean_test()
? &safe_bool_base::this_type_does_not_support_compar isons : 0;
}
protected:
~safe_bool() {}
};
template<class safe_bool<void: public safe_bool_base {
public:
operator bool_type() const {
return boolean_test()==true ?
&safe_bool_base::this_type_does_not_support_compar isons //Error!
: 0;
}
protected:
virtual bool boolean_test() const=0;
virtual ~safe_bool() {}
};
Change the line with the error to:

return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK

and the error should be fixed.

Greg

Dec 14 '06 #2

P: n/a
Greg wrote:
mlimber wrote:
In an article on the safe bool idiom
(http://www.artima.com/cppsource/safeboolP.html), Bjorn Karlsson gives
the following code (slightly modified):

class safe_bool_base {
protected:
typedef void (safe_bool_base::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}

safe_bool_base() {}
safe_bool_base(const safe_bool_base&) {}
safe_bool_base& operator=(const safe_bool_base&) {return *this;}
~safe_bool_base() {}
};

template <typename T=voidclass safe_bool : public safe_bool_base {
public:
operator bool_type() const {
return (static_cast<const T*>(this))->boolean_test()
? &safe_bool_base::this_type_does_not_support_compar isons : 0;
}
protected:
~safe_bool() {}
};
template<class safe_bool<void: public safe_bool_base {
public:
operator bool_type() const {
return boolean_test()==true ?
&safe_bool_base::this_type_does_not_support_compar isons //Error!
: 0;
}
protected:
virtual bool boolean_test() const=0;
virtual ~safe_bool() {}
};

Change the line with the error to:

return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK

and the error should be fixed.
Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?

Cheers! --M

Dec 14 '06 #3

P: n/a
mlimber wrote:
Greg wrote:

Change the line with the error to:

return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK

and the error should be fixed.

Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?
Neither one has access:

int main()
{
safe_bool<intsb;
}

error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected

Greg

Dec 14 '06 #4

P: n/a
Greg wrote:
mlimber wrote:
Greg wrote:
>
Change the line with the error to:
>
return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK
>
and the error should be fixed.
Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?

Neither one has access:

int main()
{
safe_bool<intsb;
}

error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected
The destructor is protected, indicating that safe_bool should only be
used as a base class. The derived classes should have full access to
the protected members of the base class, but it seems that only the
non-specialized derived class does. Any idea why (or is this one of the
rare bugs in Comeau)?

Cheers! --M

Dec 15 '06 #5

P: n/a

mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:

Change the line with the error to:

return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK

and the error should be fixed.
>
Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?
Neither one has access:

int main()
{
safe_bool<intsb;
}

error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected

The destructor is protected, indicating that safe_bool should only be
used as a base class. The derived classes should have full access to
the protected members of the base class, but it seems that only the
non-specialized derived class does. Any idea why (or is this one of the
rare bugs in Comeau)?
No, Comeau is correct: a derived class does not have access to
protected members of a base class - either for the purposes of
obtaining a member pointer to one or even to use the protected member
in any kind of object expression. The only protected members that a
class has that kind of access are its own protected members and the
protected members of classes that derive from it. And that rule is in
fact the reason why changing the class of the member pointer from
safe_bool_base to safe_bool eliminates the access violation.

Therefore every member pointer above that refers to a protected member
of a base class - is an access violation waiting to happen. The actual
error is deferred of course until the code in question is instantiated.
So there is nothing about the void specialization that is any different
than the others templates - they all have the same problem.

Greg

Dec 15 '06 #6

P: n/a
Greg wrote:
mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:
>
Change the line with the error to:
>
return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK
>
and the error should be fixed.

Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?
>
Neither one has access:
>
int main()
{
safe_bool<intsb;
}
>
error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected
The destructor is protected, indicating that safe_bool should only be
used as a base class. The derived classes should have full access to
the protected members of the base class, but it seems that only the
non-specialized derived class does. Any idea why (or is this one of the
rare bugs in Comeau)?

No, Comeau is correct: a derived class does not have access to
protected members of a base class - either for the purposes of
obtaining a member pointer to one or even to use the protected member
in any kind of object expression.
Can you cite the standard in this regard?
The only protected members that a
class has that kind of access are its own protected members and the
protected members of classes that derive from it.
Huh? A class can obtain a pointer to a member of a class that derives
from it? Unless you're talking only about virtual functions, you've
lost me completely.
And that rule is in
fact the reason why changing the class of the member pointer from
safe_bool_base to safe_bool eliminates the access violation.

Therefore every member pointer above that refers to a protected member
of a base class - is an access violation waiting to happen. The actual
error is deferred of course until the code in question is instantiated.
So there is nothing about the void specialization that is any different
than the others templates - they all have the same problem.
But the code given in my OP *does* instantiate both the specialized and
non-specialized versions, but only the specialized version causes the
compiler to choke.

Cheers! --M

Dec 15 '06 #7

P: n/a
Greg wrote:
mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:
>
Change the line with the error to:
>
return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK
>
and the error should be fixed.

Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?
>
Neither one has access:
>
int main()
{
safe_bool<intsb;
}
>
error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected
The destructor is protected, indicating that safe_bool should only be
used as a base class. The derived classes should have full access to
the protected members of the base class, but it seems that only the
non-specialized derived class does. Any idea why (or is this one of the
rare bugs in Comeau)?

No, Comeau is correct: a derived class does not have access to
protected members of a base class - either for the purposes of
obtaining a member pointer to one or even to use the protected member
in any kind of object expression.
Can you cite the standard in this regard?
The only protected members that a
class has that kind of access are its own protected members and the
protected members of classes that derive from it.
Huh? A class can obtain a pointer to a member of a class that derives
from it? Unless you're talking only about virtual functions, you've
lost me completely.
And that rule is in
fact the reason why changing the class of the member pointer from
safe_bool_base to safe_bool eliminates the access violation.

Therefore every member pointer above that refers to a protected member
of a base class - is an access violation waiting to happen. The actual
error is deferred of course until the code in question is instantiated.
So there is nothing about the void specialization that is any different
than the others templates - they all have the same problem.
But the code given in my OP *does* instantiate both the specialized and
non-specialized versions, but only the specialized version causes the
compiler to choke.

Cheers! --M

Dec 15 '06 #8

P: n/a
Greg wrote:
mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:
>
Change the line with the error to:
>
return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK
>
and the error should be fixed.

Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?
>
Neither one has access:
>
int main()
{
safe_bool<intsb;
}
>
error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected
The destructor is protected, indicating that safe_bool should only be
used as a base class. The derived classes should have full access to
the protected members of the base class, but it seems that only the
non-specialized derived class does. Any idea why (or is this one of the
rare bugs in Comeau)?

No, Comeau is correct: a derived class does not have access to
protected members of a base class - either for the purposes of
obtaining a member pointer to one or even to use the protected member
in any kind of object expression.
Can you cite the standard in this regard?
The only protected members that a
class has that kind of access are its own protected members and the
protected members of classes that derive from it.
Huh? A class can obtain a pointer to a member of a class that derives
from it? Unless you're talking only about virtual functions, you've
lost me completely.
And that rule is in
fact the reason why changing the class of the member pointer from
safe_bool_base to safe_bool eliminates the access violation.

Therefore every member pointer above that refers to a protected member
of a base class - is an access violation waiting to happen. The actual
error is deferred of course until the code in question is instantiated.
So there is nothing about the void specialization that is any different
than the others templates - they all have the same problem.
But the code given in my OP *does* instantiate both the specialized and
non-specialized versions, but only the specialized version causes the
compiler to choke.

Cheers! --M

Dec 15 '06 #9

P: n/a
Greg wrote:
mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:
>
Change the line with the error to:
>
return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK
>
and the error should be fixed.

Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?
>
Neither one has access:
>
int main()
{
safe_bool<intsb;
}
>
error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected
The destructor is protected, indicating that safe_bool should only be
used as a base class. The derived classes should have full access to
the protected members of the base class, but it seems that only the
non-specialized derived class does. Any idea why (or is this one of the
rare bugs in Comeau)?

No, Comeau is correct: a derived class does not have access to
protected members of a base class - either for the purposes of
obtaining a member pointer to one or even to use the protected member
in any kind of object expression.
Can you cite the standard in this regard?
The only protected members that a
class has that kind of access are its own protected members and the
protected members of classes that derive from it.
Huh? A class can obtain a pointer to a member of a class that derives
from it? Unless you're talking only about virtual functions, you've
lost me completely.
And that rule is in
fact the reason why changing the class of the member pointer from
safe_bool_base to safe_bool eliminates the access violation.

Therefore every member pointer above that refers to a protected member
of a base class - is an access violation waiting to happen. The actual
error is deferred of course until the code in question is instantiated.
So there is nothing about the void specialization that is any different
than the others templates - they all have the same problem.
But the code given in my OP *does* instantiate both the specialized and
non-specialized versions, but only the specialized version causes the
compiler to choke.

Cheers! --M

Dec 15 '06 #10

P: n/a
Greg wrote:
mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:
>
Change the line with the error to:
>
return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK
>
and the error should be fixed.

Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?
>
Neither one has access:
>
int main()
{
safe_bool<intsb;
}
>
error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected
The destructor is protected, indicating that safe_bool should only be
used as a base class. The derived classes should have full access to
the protected members of the base class, but it seems that only the
non-specialized derived class does. Any idea why (or is this one of the
rare bugs in Comeau)?

No, Comeau is correct: a derived class does not have access to
protected members of a base class - either for the purposes of
obtaining a member pointer to one or even to use the protected member
in any kind of object expression.
Can you cite the standard in this regard?
The only protected members that a
class has that kind of access are its own protected members and the
protected members of classes that derive from it.
Huh? A class can obtain a pointer to a member of a class that derives
from it? Unless you're talking only about virtual functions, you've
lost me completely.
And that rule is in
fact the reason why changing the class of the member pointer from
safe_bool_base to safe_bool eliminates the access violation.

Therefore every member pointer above that refers to a protected member
of a base class - is an access violation waiting to happen. The actual
error is deferred of course until the code in question is instantiated.
So there is nothing about the void specialization that is any different
than the others templates - they all have the same problem.
But the code given in my OP *does* instantiate both the specialized and
non-specialized versions, but only the specialized version causes the
compiler to choke.

Cheers! --M

Dec 15 '06 #11

P: n/a
Greg wrote:
mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:
>
Change the line with the error to:
>
return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK
>
and the error should be fixed.

Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?
>
Neither one has access:
>
int main()
{
safe_bool<intsb;
}
>
error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected
The destructor is protected, indicating that safe_bool should only be
used as a base class. The derived classes should have full access to
the protected members of the base class, but it seems that only the
non-specialized derived class does. Any idea why (or is this one of the
rare bugs in Comeau)?

No, Comeau is correct: a derived class does not have access to
protected members of a base class - either for the purposes of
obtaining a member pointer to one or even to use the protected member
in any kind of object expression.
Can you cite the standard in this regard?
The only protected members that a
class has that kind of access are its own protected members and the
protected members of classes that derive from it.
Huh? A class can obtain a pointer to a member of a class that derives
from it? Unless you're talking only about virtual functions, you've
lost me completely.
And that rule is in
fact the reason why changing the class of the member pointer from
safe_bool_base to safe_bool eliminates the access violation.

Therefore every member pointer above that refers to a protected member
of a base class - is an access violation waiting to happen. The actual
error is deferred of course until the code in question is instantiated.
So there is nothing about the void specialization that is any different
than the others templates - they all have the same problem.
But the code given in my OP *does* instantiate both the specialized and
non-specialized versions, but only the specialized version causes the
compiler to choke.

Cheers! --M

Dec 15 '06 #12

P: n/a
mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:

Change the line with the error to:

return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK

and the error should be fixed.
>
Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?

Neither one has access:

int main()
{
safe_bool<intsb;
}

error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected
>
The destructor is protected, indicating that safe_bool should only be
used as a base class. The derived classes should have full access to
the protected members of the base class, but it seems that only the
non-specialized derived class does. Any idea why (or is this one of the
rare bugs in Comeau)?
No, Comeau is correct: a derived class does not have access to
protected members of a base class - either for the purposes of
obtaining a member pointer to one or even to use the protected member
in any kind of object expression.

Can you cite the standard in this regard?
11.5 is the relevant section of the Standard:

"As described earlier, access to a protected member is granted because
the reference occurs in a friend or member of some class C. If the
access is to form a pointer to member (5.3.1), the
nested-name-specifier shall name C or a class derived from C. All other
accesses involve a (possibly implicit) object expression (5.2.5). In
this case, the class of the object expression shall be C or a class
derived from C."

Of course the members of an object include those members (if any) that
it inherits from any of its base classes; and for this reason we think
of "protected" access as allowing access to a class's members by its
derived classes - but strictly speaking, that view is not completely
accurate because the access to the member is always indirect - through
the derived class member - and not a direct access to the protected
member of the base class - as the error in the above program makes
clear.

Greg

Dec 15 '06 #13

P: n/a
Sorry about the reposting. Google was having issues.

Cheers! --M

Dec 15 '06 #14

P: n/a
Greg wrote:
mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:
mlimber wrote:
Greg wrote:
>
Change the line with the error to:
>
return boolean_test()==true ?
&safe_bool::this_type_does_not_support_comparis ons
: 0; // OK
>
and the error should be fixed.

Indeed. Now the question is, Why could the normal template class get to
that member but the explicit specialization could not?
>
Neither one has access:
>
int main()
{
safe_bool<intsb;
}
>
error: 'safe_bool<T>::~safe_bool() [with T = int]' is protected

The destructor is protected, indicating that safe_bool should only be
used as a base class. The derived classes should have full access to
the protected members of the base class, but it seems that only the
non-specialized derived class does. Any idea why (or is this one ofthe
rare bugs in Comeau)?
>
No, Comeau is correct: a derived class does not have access to
protected members of a base class - either for the purposes of
obtaining a member pointer to one or even to use the protected member
in any kind of object expression.
Can you cite the standard in this regard?

11.5 is the relevant section of the Standard:

"As described earlier, access to a protected member is granted because
the reference occurs in a friend or member of some class C. If the
access is to form a pointer to member (5.3.1), the
nested-name-specifier shall name C or a class derived from C. All other
accesses involve a (possibly implicit) object expression (5.2.5). In
this case, the class of the object expression shall be C or a class
derived from C."

Of course the members of an object include those members (if any) that
it inherits from any of its base classes; and for this reason we think
of "protected" access as allowing access to a class's members by its
derived classes - but strictly speaking, that view is not completely
accurate because the access to the member is always indirect - through
the derived class member - and not a direct access to the protected
member of the base class - as the error in the above program makes
clear.

Greg
Ok, I get it now. Thanks for your help. BTW, the error does show up in
both versions if they are instantiated:

int main()
{
Testable_with_virtual twv;
Testable_without_virtual twov;
if( twv && twov ) return 1;
return 0;
}

Cheers! --M

Jan 3 '07 #15

This discussion thread is closed

Replies have been disabled for this discussion.