class B : public A
{
public:
void Bar(const A& a)
{
a.Foo();
}
};
test.cpp: In member function ‘void B::Bar(const A&)’:
test.cpp:4: error: ‘void A::Foo() const’ is protected
test.cpp:12: error: within this context
I thought the whole point of protected was so that inherited classes could use certain member variables/functions, but keep them off-limits from others.
>>10
I'd argue that what that's not what it's doing. Say we have this simple class.
class A
{
void Foo() const {}
public:
void Bar(const A& a)
{
a.Foo();
}
};
That's legal, as it ought to be--an A object can send a private message to any other A object. In my example >>9, why shouldn't a B object be able to send a protected message to any other A object, since a B is an A?
Name:
Anonymous2008-12-08 21:56
>>11
Perhaps because it might not be the same exact kind of A that the other A is. Either way, you're using Sepples now, just give in and stop expecting things to make sense.
Name:
Anonymous2008-12-09 5:08
>>12
So the "is a" relation is completely broken in Sepples? Figures.
Name:
Anonymous2008-12-09 8:05
>>13
Java behaves the same way, so it can't be broken.
Name:
Anonymous2008-12-09 8:07
What the fuck is the difference between template <class T> and template <typename T>. If there is no difference, WHY SUPPORT BOTH FOR FUCK'S SHIT?. Backwards compatibility is not good enough an answer.
typename A<T>::Foo foo; PIG DISGUSTING. A<T>::Foois already a god damn class. What does the compiler need the typename for?
Name:
Anonymous2008-12-09 10:46
>>9
Learn the difference between the different types of inheritance in Sepples.
Name:
Anonymous2008-12-09 10:48
>>15
Sepples has a badly defined, ambiguous grammar. That's why.
NEVER FORGET THE HEROES THAT GAVE THEIR TIME AND THEIR LIVES TO DIE FOR THE GREATER CAUSE OF MAKING THE PLEASURE OF BEING CUMMED INSIDE A GOOGLE MEME. YOUR SACRIFICE WILL NOT BE FORGOTTEN.
NVR FGT
Name:
Anonymous2008-12-09 13:54
>>15
Stolen from: Thinking in C++, vol.2, Ch.6, The typename keyword Consider the following: //: C06:TypenamedID.cpp // Using 'typename' to say it's a type, // and not something other than a type //{L} ../TestSuite/Test
template<class T> class X { // Without typename, you should get an error: typename T::id i; public: void f() { i.g(); } };
class Y { public: class id { public: void g() {} }; };
int main() { Y y; X<Y> xy; xy.f(); } ///:~
The template definition assumes that the class T that you hand it must have a nested identifier of some kind called id. But id could be a member object of T, in which case you can perform operations on id directly, but you couldn’t “create an object” of “the type [code]id.” However, that’s exactly what is happening here: the identifier id is being treated as if it were actually a nested type inside T. In the case of class Y, id is in fact a nested type, but (without the typename keyword) the compiler can’t know that when it’s compiling X.
If, when it sees an identifier in a template, the compiler has the option of treating that identifier as a type or as something other than a type, then it will assume that the identifier refers to something other than a type. That is, it will assume that the identifier refers to an object (including variables of primitive types), an enumeration or something similar. However, it will not – cannot – just assume that it is a type. Thus, the compiler gets confused when we pretend it’s a type.
The typename keyword tells the compiler to interpret a particular name as a type. It must be used for a name that:
1. Is a qualified name, one that is nested within another type. 2. Depends on a template argument. That is, a template argument is somehow involved in the name. The template argument causes the ambiguity when the compiler makes the simplest assumption: that the name refers to something other than a type.
Because the default behavior of the compiler is to assume that a name that fits the above two points is not a type, you must use typename even in places where you think that the compiler ought to be able to figure out the right way to interpret the name on its own. In the above example, when the compiler sees T::id, it knows (because of the typename keyword) that id refers to a nested type and thus it can create an object of that type.
The short version of the rule is: if your type is a qualified name that involves a template argument, you must use typename.
Name:
Anonymous2008-12-09 14:02
>>19
I ask, why is typename required by Sepples in that context", you answer typename is required
Gee, thanks anyway. I mean, for fucking shit's sake, what could T::id stand for, if not a type? The trailing i make is pretty god damn unambiguous.
Name:
Anonymous2008-12-09 14:07
>>20
Bad reading comprehension? READ THE FUCKING TEXT AGAIN!
>>21
All right I've read it. I still think T::id i is unambiguous, typename is there just to make compiler design easier. Those FUCKING slackers.
Name:
Anonymous2008-12-09 14:34
>>23
Write a better one then. It's not rocket science, right?
Name:
Anonymous2008-12-09 14:43
>>24
I would, but it wouldn't adhere to the standard. It's Sepples' failure, not the compiler's failure. Of course, if you can come up with a context where the meaning of T::id is ambiguous, you will be an triumphant of INTERNETS, and this thread in particular.
template <class T>
class A {
public:
void f() {
cout << "lol sepples" << endl;
}
};
template <class T>
class B : public A<T> {
public:
void g() {
f();
}
};
int main() {
B<int> b;
b.g();
}[code]
[code]sepples.cpp: In member function ‘void B<T>::g()’:
sepples.cpp:17: error: there are no arguments to ‘f’ that depend on a template parameter, so a declaration of ‘f’ must be available
Name:
Anonymous2008-12-09 15:30
>>26
Well I guess the context insensitive typename solution sure repairs Sepples' already FUBAR grammar. All right, you win. Congratulations.
>>27
This error actually caused me a great deal of annoyance. It worked in one compiler, but not another. I switched to:
template<class T>
struct Templategasm {
struct A { void f() { } };
struct B : A { void g() { f(); } };
};
int main() {
Templategasm<int>::B b;
b.g();
}
rather than explicitly qualifying names everywhere (it's still needed in some places, but it's generally more readable). It works because A becomes a non-dependent base class in Sepplespeak, and is thus checked when looking for non-dependent names. Talk about PIG DISGUSTING.
>>30
I prefer a typedef, like STL.
template<class T>
struct Templategasm {
struct A { void f() { } };
};
int main() {
typedef Templategasm<int>::A A_int
A_int a;
a.g();
}
Still pig disgusting but it's more readable and doesn't depend on the compiler optimization too much.
#include "prog.h"
using namespace std;
template<class A, class R>
struct Hax :
unary_function<A, R>
{
typedef R result_t;
typedef A argument_t;
result_t
operator()(const argument_t& a)
const
{
// TODO Hax
return result_t(a.anus);
}
};
struct Anus
{
}
struct Poster
{
Anus anus;
};
struct HaxxedAnus
{
HaxxedAnus(Anus& a)
{
/* The pleasure of being cummed inside */
}
};
>>11
Inheritance does not mean access. When you derived B from A you inherited the Foo function, so every B has its own Foo to call. This does not mean that nonlocal A's have to give access to their protected methods in B methods now.
Whereas your other example has nothing to do with this at all. Foo is used within one of the other class methods. Nothing wrong with that.
Name:
Anonymous2008-12-10 1:19
>>37
I get how it works now, but I guess that protected wasn't explained well to me before. I think some sort of access level like I want should exist--like protected, but lets derived classes call the methods/use the variables of objects of the base class.