multiple inheritance ambiguity question

P

PuzzledwithC++

HI,

consider the code below

class base
{
public:
void display()
{ }
};
class der1:public base
{
};
class der2:public base
{
};

class client :public der1,public der2
{
public:
void test()
{
//display();//ambigous call.Compilation error.
base::display();//no compilation error.
}
};
void main()
{
client cl;
cl.test();

}

So calling display() inside client::test() will give a valid
compilation error.
But when I call base::display(),the program runs fine.
My confusion is when I call base::display(),which base is being
recognized here?.Is it a base part from der1 or der2.?
I believe the call base::display() gets modified like
static_cast<der1*>(this)->base::display().


Thanks and regards,
Yogesh
 
V

Vladimir Jovic

PuzzledwithC++ said:
HI,

consider the code below

class base
{
public:
void display()
{ }
};
class der1:public base
{
};
class der2:public base
{
};

class client :public der1,public der2
{
public:
void test()
{
//display();//ambigous call.Compilation error.
base::display();//no compilation error.
}
};
void main()
{
client cl;
cl.test();

}

So calling display() inside client::test() will give a valid
compilation error.
But when I call base::display(),the program runs fine.
My confusion is when I call base::display(),which base is being
recognized here?.Is it a base part from der1 or der2.?
I believe the call base::display() gets modified like
static_cast<der1*>(this)->base::display().

That is in the faq:
http://www.parashift.com/c++-faq-lite/multiple-inheritance.html
 
J

Joshua Maurice

HI,

consider the code below

class base
{
public:
     void display()
     { }};

class der1:public base
{};

class der2:public base
{

};

class client :public der1,public der2
{
  public:
          void test()
          {
            //display();//ambigous call.Compilation error.
            base::display();//no compilation error.
           }};

void main()
{
   client cl;
   cl.test();

}

So calling display() inside client::test() will give a valid
compilation error.
But when I call base::display(),the program runs fine.
My confusion is when I call base::display(),which base is being
recognized here?.Is it a base part from der1 or der2.?
I believe the call base::display() gets modified like
static_cast<der1*>(this)->base::display().

Your compiler is broken. Which is it?

Also, for simple things, try
http://www.comeaucomputing.com/tryitout/
It's the closest thing to a reference implementation we have. When I
put in your code, it gives:

Your Comeau C/C++ test results are as follows:

Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for
ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 23: error: base class "base" is ambiguous
base::display();//no compilation error.
^

"ComeauTest.c", line 27: error: return type of function "main" must be
"int"
So use int main() OR int main(int argc, char *argv[])
void main()
^

2 errors detected in the compilation of "ComeauTest.c".
 
F

Francesco S. Carta

consider the code below
class base
{
public:
     void display()
     { }};
class der1:public base
{};
class der2:public base
{

class client :public der1,public der2
{
  public:
          void test()
          {
            //display();//ambigous call.Compilation error.
            base::display();//no compilation error.
           }};
void main()
{
   client cl;
   cl.test();

So calling display() inside client::test() will give a valid
compilation error.
But when I call base::display(),the program runs fine.
My confusion is when I call base::display(),which base is being
recognized here?.Is it a base part from der1 or der2.?
I believe the call base::display() gets modified like
static_cast<der1*>(this)->base::display().

Your compiler is broken. Which is it?

Also, for simple things, tryhttp://www.comeaucomputing.com/tryitout/
It's the closest thing to a reference implementation we have. When I
put in your code, it gives:

Your Comeau C/C++ test results are as follows:

Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for
ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 23: error: base class "base" is ambiguous
              base::display();//no compilation error.
              ^

"ComeauTest.c", line 27: error: return type of function "main" must be
"int"
        So use int main() OR int main(int argc, char *argv[])
  void main()
       ^

2 errors detected in the compilation of "ComeauTest.c".

Well, I think that also Comeau gets :: base specifications wrong if
fed with something even slightly more complex, see this:

-------
struct base1{ void display(){} };
struct base2{ void display(){} };
struct der1 : base1, base2 {};
struct der2 : base1, base2 {};
struct client : der1, der2 {};
int main() {
/*
tested with
- gcc 3.4.5
- Comeau Online
both choke on last three statements
*/

client cl;
der1* p_der1 = &cl;
base1* p_base1 = p_der1;

/* compiles, OK */
p_base1->display();

/* compile error: ambiguous (OK) */
cl.display();

/* compile error: ambiguous (OK) */
cl.der1::display();

/* compile error: ambiguous (BUG???) */
cl.der1::base1::display();
}

-------

Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for
ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 22: error: "client::display" is ambiguous
cl.display();
^

"ComeauTest.c", line 25: error: "der1::display" is ambiguous
cl.der1::display();
^

"ComeauTest.c", line 28: error: base class "base1" is ambiguous
cl.der1::base1::display();
^

3 errors detected in the compilation of "ComeauTest.c".

In strict mode, with -tused, Compile failed
Hit the Back Button to review your code and compile options.
Compiled with C++0x extensions enabled.
 
J

Joshua Maurice

Well, I think that also Comeau gets :: base specifications wrong if
fed with something even slightly more complex, see this:

-------
struct base1{ void display(){} };
struct base2{ void display(){} };
struct der1 : base1, base2 {};
struct der2 : base1, base2 {};
struct client : der1, der2 {};
int main() {
    /*
    tested with
        - gcc 3.4.5
        - Comeau Online
    both choke on last three statements
    */

    client cl;
    der1* p_der1 = &cl;
    base1* p_base1 = p_der1;

    /* compiles, OK */
    p_base1->display();

    /* compile error: ambiguous (OK) */
    cl.display();

    /* compile error: ambiguous (OK) */
    cl.der1::display();

    /* compile error: ambiguous (BUG???) */
    cl.der1::base1::display();

}

-------

Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for
ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 22: error: "client::display" is ambiguous
      cl.display();
         ^

"ComeauTest.c", line 25: error: "der1::display" is ambiguous
      cl.der1::display();
               ^

"ComeauTest.c", line 28: error: base class "base1" is ambiguous
      cl.der1::base1::display();
      ^

3 errors detected in the compilation of "ComeauTest.c".

In strict mode, with -tused, Compile failed
Hit the Back Button to review your code and compile options.
Compiled with C++0x extensions enabled.

Odd.
gcc version 4.1.2 20070626 (Red Hat 4.1.2-14)
just choked on that too.
foo.cpp: In function ‘int main()’:
foo.cpp:22: error: request for member ‘display’ is ambiguous
foo.cpp:2: error: candidates are: void base2::display()
foo.cpp:1: error: void base1::display()
foo.cpp:2: error: void base2::display()
foo.cpp:1: error: void base1::display()
foo.cpp:25: error: request for member ‘display’ is ambiguous
foo.cpp:2: error: candidates are: void base2::display()
foo.cpp:1: error: void base1::display()
foo.cpp:28: error: ‘base1’ is an ambiguous base of ‘client’
I am also confused as I agree with your assessment Francesco. Line 28
should not be ambiguous, at least as I understand the language rules.
I'm leaning towards my understanding is flawed. Let me go see what the
standard says...
 
A

Alf P. Steinbach

* Joshua Maurice:
Odd.
gcc version 4.1.2 20070626 (Red Hat 4.1.2-14)
just choked on that too.
foo.cpp: In function ‘int main()’:
foo.cpp:22: error: request for member ‘display’ is ambiguous
foo.cpp:2: error: candidates are: void base2::display()
foo.cpp:1: error: void base1::display()
foo.cpp:2: error: void base2::display()
foo.cpp:1: error: void base1::display()
foo.cpp:25: error: request for member ‘display’ is ambiguous
foo.cpp:2: error: candidates are: void base2::display()
foo.cpp:1: error: void base1::display()
foo.cpp:28: error: ‘base1’ is an ambiguous base of ‘client’
I am also confused as I agree with your assessment Francesco. Line 28
should not be ambiguous, at least as I understand the language rules.
I'm leaning towards my understanding is flawed. Let me go see what the
standard says...

The qualifications do not constitute a hint about which 'this' pointer to pass.
They merely specify /a/ class (the final one in the qualification chain) where
to look up the 'display' name. As far as the compiler is concerned the whole
qualification chain 'der1::base1' is equivalent to writing just 'base1::'.

Cheers & hth.,

- Alf
 
F

Francesco S. Carta

* Joshua Maurice:





The qualifications do not constitute a hint about which 'this' pointer to pass.
They merely specify /a/ class (the final one in the qualification chain) where
to look up the 'display' name. As far as the compiler is concerned the whole
qualification chain 'der1::base1' is equivalent to writing just 'base1::'..

So then, which is the working way to access that member, other than
that manual pointer climbing I've used in my snippet above?

I strongly hope that the Standard _does_ mandate implementations to
compile line 28.

That would be really odd otherwise: the qualification does fully
specify which base to use for that call, the compiler should be able
to resolve it.
 
G

Gert-Jan de Vos

So then, which is the working way to access that member, other than
that manual pointer climbing I've used in my snippet above?

This should work:

static_cast said:
That would be really odd otherwise: the qualification does fully
specify which base to use for that call, the compiler should be able
to resolve it.

As Alf explained: the qualification just resolves which function to
call, not on which base1 subobject of the cl object.
 
F

Francesco S. Carta

This should work:

static_cast<base1&>(static_cast<der1&>(cl)).display();

Fine, equivalent to the pointer thingie, but once I'm there, I could
even write:

-------
typedef base1& to_base1;
typedef der1& to_der1;
to_base1(to_der1(cl)).display();
-------
As Alf explained: the qualification just resolves which function to
call, not on which base1 subobject of the cl object.

Fine, I understand that compilers plainly ignore part of the
qualification, the problem is whether they are meant to behave so or
not, according to the Standard. It seems trivial to resolve a
duplicate base in that way (using qualification, which is meant also
to resolve ambiguities), that shouldn't be a problem to implement.
 
F

Francesco S. Carta

Fine, equivalent to the pointer thingie, but once I'm there, I could
even write:

-------
    typedef base1& to_base1;
    typedef der1& to_der1;
    to_base1(to_der1(cl)).display();
-------



Fine, I understand that compilers plainly ignore part of the
qualification, the problem is whether they are meant to behave so or
not, according to the Standard. It seems trivial to resolve a
duplicate base in that way (using qualification, which is meant also
to resolve ambiguities), that shouldn't be a problem to implement.

I'm bringing this issue to comp.std.c++
 
F

Francesco S. Carta

I'm bringing this issue to comp.std.c++

OK, as it seems, I was too optimistic about this.

It turns out that the last line of my example _must_ be considered as
ill-formed, according to the Standard.

This really hit me, because TC++PL 3rd edition presents some examples
which seem really reasonable, but which are expected to be rejected by
the current Standard.

As I wrote on comp.std.c++, the book predates the current Standard and
things must have changed about this stuff, under the Standardization
Committee's eyes.
 
B

Balog Pal

"Francesco S. Carta"
It turns out that the last line of my example _must_ be considered as
ill-formed, according to the Standard.

You seem to miss how :: works and groups. And that is about finding
*names* only while you wanted them to linger on after the name was selected.
This really hit me, because TC++PL 3rd edition presents some examples
which seem really reasonable, but which are expected to be rejected by
the current Standard.

As far I I saw the examples they are nowhere identical to yours, and does
not have similar problems. And work fine with the standard too.
 
F

Francesco S. Carta

Balog Pal said:
"Francesco S. Carta"


You seem to miss how :: works and groups. And that is about finding
*names* only while you wanted them to linger on after the name was selected.

10.1 [class.mi] 4:

"In such lattices, explicit qualification can be used to specify which
subobject is meant."

Where "such lattices" refers to this example, given in 10.1 [class.mi]
3:
-------
class L { public: int next; /* ... */ };
class A : public L { /* ... */ };
class B : public L { /* ... */ };
class C : public A, public B { void f(); /* ... */ };
-------

Right after the above sentence, the Standard continues with:

"The body of function C::f could refer to the member next of each L
subobject:
void C::f() { A::next = B::next; }
Without the A:: or B:: qualifiers, the definition of C::f above would
be ill-formed because of ambiguity (class.member.lookup)."

As you can see from the above wording, the qualification is not only
about names, but also, in such cases, about disambiguating subobjects.

Notice that the above example, of course, works fine both
theoretically (under the Standard's light) and practically (it does
compile, indeed).

That example happens to have the identical structure of the example
given below, taken from TC++PL 3rd ed., read on please.
As far I I saw the examples they are nowhere identical to yours, and does
not have similar problems. And work fine with the standard too.

From TC++PL 3rd ed., 15.2.3:

-------
struct Link {
Link* next;
};

class Task : public Link {
// ...
};

class Displayed : public Link {
// ...
};

// this is given in 15.2.2:
class Satellite : public Task, public Displayed {
// ...
};

void mess_with_links(Satellite* p) {
p->Task::Link::next = 0;
p->Displayed::Link::next = 0;
}
-------

According to (my understanding of) the Standard, in both of these
expressions...
-------
p->Task::Link::next = 0;
p->Displayed::Link::next = 0;
-------
....the "naming class" is "Link" (that is, the nested class in the
qualification chain), and since a Satellite cannot be implicitly
converted into a Link, those expressions are ill-formed (according to
11.2 [class.access.base] 5).

Actually, the above example doesn't compile in Comeau Online.

Notice how Stroustrup uses a redundant qualification, while the
Standard doesn't - it disambiguates the call without putting L (the
equivalent of Link) in the qualification chain.

As I said in comp.std.c++: "It would be nice if implementations could
allow redundant qualifications in such cases, and it would be even
nicer if a multiple ambiguity such as the one of my example could be
resolved only by climbing the qualification chain, but that would mean
changing the wording in 11.2/4 [errata corrige: I meant to write
"11.2/5"], and I'm not going to propose it."

By the way, I never said that that TC++PL example was identical to my
example - just in case...

Memory must have tricked me, because in some posts I spoke about
"examples" (plural) while I was able to find only one example that
doesn't compile and that doesn't comply to the Standard (about this
very subject).
 
F

Francesco S. Carta

Balog Pal said:
"Francesco S. Carta"


You seem to miss how :: works and groups. And that is about finding
*names* only while you wanted them to linger on after the name was selected.

10.1 [class.mi] 4:

"In such lattices, explicit qualification can be used to specify which
subobject is meant."

Where "such lattices" refers to this example, given in 10.1 [class.mi]
3:
-------
class L { public: int next; /* ... */ };
class A : public L { /* ... */ };
class B : public L { /* ... */ };
class C : public A, public B { void f(); /* ... */ };
-------

Right after the above sentence, the Standard continues with:

"The body of function C::f could refer to the member next of each L
subobject:
void C::f() { A::next = B::next; }
Without the A:: or B:: qualifiers, the definition of C::f above would
be ill-formed because of ambiguity (class.member.lookup)."

As you can see from the above wording, the qualification is not only
about names, but also, in such cases, about disambiguating subobjects.

Notice that the above example, of course, works fine both
theoretically (under the Standard's light) and practically (it does
compile, indeed).

That example happens to have the identical structure of the example
given below, taken from TC++PL 3rd ed., read on please.
As far I I saw the examples they are nowhere identical to yours, and does
not have similar problems. And work fine with the standard too.

From TC++PL 3rd ed., 15.2.3:

-------
struct Link {
Link* next;
};

class Task : public Link {
// ...
};

class Displayed : public Link {
// ...
};

// this is given in 15.2.2:
class Satellite : public Task, public Displayed {
// ...
};

void mess_with_links(Satellite* p) {
p->Task::Link::next = 0;
p->Displayed::Link::next = 0;
}
-------

According to (my understanding of) the Standard, in both of these
expressions...
-------
p->Task::Link::next = 0;
p->Displayed::Link::next = 0;
-------
....the "naming class" is "Link" (that is, the nested class in the
qualification chain), and since a Satellite cannot be implicitly
converted into a Link, those expressions are ill-formed (according to
11.2 [class.access.base] 5).

Actually, the above example doesn't compile in Comeau Online.

Notice how Stroustrup uses a redundant qualification, while the
Standard doesn't - it disambiguates the call without putting L (the
equivalent of Link) in the qualification chain.

As I said in comp.std.c++: "It would be nice if implementations could
allow redundant qualifications in such cases, and it would be even
nicer if a multiple ambiguity such as the one of my example could be
resolved only by climbing the qualification chain, but that would mean
changing the wording in 11.2/4 [errata corrige: I meant to write
"11.2/5"], and I'm not going to propose it."

Of course, I never said that that TC++PL example was identical to my
example.

Memory must have tricked me, because in I spoke about
"examples" (plural) while I was able to find only one example that
doesn't compile and that doesn't comply to the Standard (about this
very subject).
 
B

Balog Pal

"Francesco S. Carta"
You seem to miss how :: works and groups. And that is about finding
*names* only while you wanted them to linger on after the name was
selected.

10.1 [class.mi] 4:

"In such lattices, explicit qualification can be used to specify which
subobject is meant."

Where "such lattices" refers to this example, given in 10.1 [class.mi]
3:
-------
class L { public: int next; /* ... */ };
class A : public L { /* ... */ };
class B : public L { /* ... */ };
class C : public A, public B { void f(); /* ... */ };
-------

Right after the above sentence, the Standard continues with:

"The body of function C::f could refer to the member next of each L
subobject:
void C::f() { A::next = B::next; }
Without the A:: or B:: qualifiers, the definition of C::f above would
be ill-formed because of ambiguity (class.member.lookup)."

As you can see from the above wording, the qualification is not only
about names, but also, in such cases, about disambiguating subobjects.

Yes it is. Here A and B on the left of ::, being *distinct* types can do the
job.

In your examples you use the *same* type, that is not good to tell a
difference.
Notice that the above example, of course, works fine both
theoretically (under the Standard's light) and practically (it does
compile, indeed).

That example happens to have the identical structure of the example
given below, taken from TC++PL 3rd ed., read on please.


From TC++PL 3rd ed., 15.2.3:

-------
struct Link {
Link* next;
};

class Task : public Link {
// ...
};

class Displayed : public Link {
// ...
};

// this is given in 15.2.2:
class Satellite : public Task, public Displayed {
// ...
};

void mess_with_links(Satellite* p) {
p->Task::Link::next = 0;
p->Displayed::Link::next = 0;
}
-------

Ah, Bjarne really messed up the example, he certainly meant
p->Task::next = 0;
p->Displayed::next = 0;

that should work fine.
According to (my understanding of) the Standard, in both of these
expressions...
-------
p->Task::Link::next = 0;
p->Displayed::Link::next = 0;
-------
...the "naming class" is "Link" (that is, the nested class in the
qualification chain), and since a Satellite cannot be implicitly
converted into a Link, those expressions are ill-formed (according to
11.2 [class.access.base] 5).

Actually, the above example doesn't compile in Comeau Online.

Notice how Stroustrup uses a redundant qualification, while the
Standard doesn't - it disambiguates the call without putting L (the
equivalent of Link) in the qualification chain.

Yes, and that extra qual does nothing good to the example.
As I said in comp.std.c++: "It would be nice if implementations could
allow redundant qualifications in such cases, and it would be even
nicer if a multiple ambiguity such as the one of my example could be
resolved only by climbing the qualification chain, but that would mean
changing the wording in 11.2/4 [errata corrige: I meant to write
"11.2/5"], and I'm not going to propose it."

IMO it would be even nicer BY FAR if we just could use :: directly with
*instances* not just types. The compiler knows the type anyway. (with the
next standard it can be hacked together via decltype, still not noce as the
normal way.) Then it could be used to naturally solve problems like in your
example, and importantly, many real ones too.

I see little value in changing the existing way for a little artificial
gain, making it easier to work with hierarchies built on guidelines from the
'no-no list'.
By the way, I never said that that TC++PL example was identical to my
example - just in case...

Ok.
 
F

Francesco S. Carta

Balog Pal said:
"Francesco S. Carta"
10.1 [class.mi] 4:
"In such lattices, explicit qualification can be used to specify which
subobject is meant."
Where "such lattices" refers to this example, given in 10.1 [class.mi]
3:
-------
class L { public: int next; /* ... */ };
class A : public L { /* ... */ };
class B : public L { /* ... */ };
class C : public A, public B { void f(); /* ... */ };
-------
Right after the above sentence, the Standard continues with:
"The body of function C::f could refer to the member next of each L
subobject:
void C::f() { A::next = B::next; }
Without the A:: or B:: qualifiers, the definition of C::f above would
be ill-formed because of ambiguity (class.member.lookup)."
As you can see from the above wording, the qualification is not only
about names, but also, in such cases, about disambiguating subobjects.

Yes it is. Here A and B on the left of ::, being *distinct* types can do the
job.

In your examples you use the *same* type, that is not good to tell a
difference.

Putting the Standard apart for a moment, my point was that my
qualification chain was clear and sufficient to disambiguate the call /
to programmers' eyes/. Then, having realized that the compiler didn't
accept it, I wondered about what the Standard mandated for such
qualifications.

It turned out what it turned out: ill-formed. Not that I care that
much - it isn't a problem at all, it can easily worked around - that's
just something that could easily work - I still believe it would be
trivial to implement, but of course, being just a dust-grain above the
"compiler-implementation-ignorant" level, I could be perfectly
wrong ;-)
Ah, Bjarne really messed up the example, he certainly meant


that should work fine.

Actually, at the time that example has been published, the
Standardization Committee didn't publish the Standard yet (if I'm not
completely mistaken, which can be, indeed), hence it is quite
plausible that Bjarne really meant to write that redundant
qualification.

As well, it is quite possible that his personal compiler did (and
eventually still does) accept and correctly use that qualification
chain - that would be something like a non-compliant extension, wrt
the current Standard... whatever, he does know his job far better than
I do ;-)

I've had a look to the 1996 draft here:
http://www.slac.stanford.edu/BFROOT/www/Computing/Environment/Standards/C++/cd2
[consider that TC++PL 3rd ed. dates back to 1997]

11.2/5 does not appear in that draft - and that's the clause that
finally defines my example as ill-formed.

About this very issue, (1996)11.2/4 covers it insufficiently - look at
the last point of that list, it reads: "-- there exists a base class B
of N that is accessible [...]". Notice how it reads "a base" and not
something more specific along the lines of "one single base" or "one
unambiguous base".

The subsequent example states, in a comment: "Okay: B* can be
implicitly cast to A*", but that's a comment in an example, that's not
within the normative text.

I believe that all of this stuff wasn't really well defined at that
time, otherwise they wouldn't have added 11.2/5 - which puts a final
word on it.

My supposition, once more, is that Bjarne stood on a position very
similar to mine, that is, that the qualification chain could be used
to unequivocally resolve a duplicated base class - a very airborne
supposition of mine, explicitly marked as such ;-)
According to (my understanding of) the Standard, in both of these
expressions...
-------
p->Task::Link::next = 0;
p->Displayed::Link::next = 0;
-------
...the "naming class" is "Link" (that is, the nested class in the
qualification chain), and since a Satellite cannot be implicitly
converted into a Link, those expressions are ill-formed (according to
11.2 [class.access.base] 5).
Actually, the above example doesn't compile in Comeau Online.
Notice how Stroustrup uses a redundant qualification, while the
Standard doesn't - it disambiguates the call without putting L (the
equivalent of Link) in the qualification chain.

Yes, and that extra qual does nothing good to the example.

You're perfectly right - but what about my example? Putting apart the
current Standard for a moment, wouldn't have you looked at my
qualification chain as a perfectly sufficient way to disambiguate that
duplicated base class?

(I'm repeating myself, I know, but here I wanted to make it a direct
question).
As I said in comp.std.c++: "It would be nice if implementations could
allow redundant qualifications in such cases, and it would be even
nicer if a multiple ambiguity such as the one of my example could be
resolved only by climbing the qualification chain, but that would mean
changing the wording in 11.2/4 [errata corrige: I meant to write
"11.2/5"], and I'm not going to propose it."

IMO it would be even nicer BY FAR if we just could use :: directly with
*instances* not just types. The compiler knows the type anyway. (with the
next standard it can be hacked together via decltype, still not noce as the
normal way.) Then it could be used to naturally solve problems like in your
example, and importantly, many real ones too.

Along the same lines: every time the compiler can unambiguously
resolve things for us, the burden should be carried by the compiler,
not by the programmer.
I see little value in changing the existing way for a little artificial
gain, making it easier to work with hierarchies built on guidelines from the
'no-no list'.

As I said, proposing such a change was completely out of my purposes.
Once I realized what the Standard really mandated, I put a full stop
on it - we're discussing this further because you called me on that,
and the discussion is interesting indeed (I discovered some new
things, meanwhile), decisively more light for me, I'm happy you posted
that reply.

And finally: yes, the hierarchy I exemplified is weird. I fully agree.

Maybe some example where it could be reasonable could exist, but this
is a completely different pair of trousers, my point here was only
about the availability of such a feature.

Perhaps they have decided on this direction also to discourage such
hierarchy designs?
That would be perfectly possible and reasonable.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top