Is this using-declaration ill-formed?

  • Thread starter Johannes Schaub (litb)
  • Start date
J

Johannes Schaub (litb)

14.5.2/7: "A using-declaration in a derived class cannot refer to a
specialization of a template conversion function in a base class."

Does this make the following code ill-formed?

struct A {
template<typename T> operator T();
operator int();
};

struct B : A { using A::eek:perator int; };
 
J

Johannes Schaub (litb)

Johannes said:
14.5.2/7: "A using-declaration in a derived class cannot refer to a
specialization of a template conversion function in a base class."

Does this make the following code ill-formed?

struct A {
template<typename T> operator T();
operator int();
};

struct B : A { using A::eek:perator int; };

There are two interpretations of this:

- If the use of the name in a using declaration results in refering to the
specialization of a template conversion function, or results in an overload
set that includes such a specialization, the program is ill-formed because a
using-declaration cannot refer to such a function.

- To determine the meaning of the name used in a using declaration, template
conversion functions are ignored, because a using declaration cannot refer
to a specialization of it, nor (in c++03) to the template itself.

Both interpretation look viable to me. The note at 7.3.3/4 indicates that
the second option is taken (and my code would be wellformed then), but is
there a normative ground for that interpretation - maybe an inherent implied
meaning of "cannot" in international standards?

By purely taking the normative wording, both options look roughly equally
viable to me, and the first looks even a bit more viable.
 
J

Johannes Schaub (litb)

Johannes said:
There are two interpretations of this:

- If the use of the name in a using declaration results in refering to the
specialization of a template conversion function, or results in an
overload set that includes such a specialization, the program is
ill-formed because a using-declaration cannot refer to such a function.

- To determine the meaning of the name used in a using declaration,
template conversion functions are ignored, because a using declaration
cannot refer to a specialization of it, nor (in c++03) to the template
itself.

I should correct: You can refer to the template itself in C++03 too, but it
makes rather little sense to write such a conversion function where you can:

struct A { template<typename T> operator int(); };
struct B : A { using A::eek:perator int; };

Valid, but since "T" is nondeduced, the utility of it is very doubtly. C++0x
allows for it to have a default argument...
 
G

Gil

I believe your code is ill formed.
to me 14.5.2/7 is just a clarification of a special case of 7.3.3/5.

struct B : A { using A::eek:perator _no_name_<int>; } //ill formed
7.3.3/5

so my interpretation is 14.5.2/7 should be moved to 7.3.3/5 explaining
that specialization of conversion operators are still considered
template-id _as_if they would have a name.

as I see it, the fact that specializations of member templates for
conversion functions are not found by name lookup is a totally
different issue, unrelated to 14.5.2/7. that's why the note about it
in 7.3.3/4 looks misplaced to me.
 
J

Johannes Schaub (litb)

Johannes said:
There are two interpretations of this:

- If the use of the name in a using declaration results in refering to the
specialization of a template conversion function, or results in an
overload set that includes such a specialization, the program is
ill-formed because a using-declaration cannot refer to such a function.

- To determine the meaning of the name used in a using declaration,
template conversion functions are ignored, because a using declaration
cannot refer to a specialization of it, nor (in c++03) to the template
itself.

I guess i'm too fast with pressing "send" with non-moderated groups :) Here
is what i sent to comp.std.c++, which is more what i meant to write. Please
forgive my many follow-self-answers. I'm really a bloody usenet-
nonmoderated-groups starter:

##################################

I see two interpretations:

Option 1:
----------

- During determining the meaning of the name, argument deduction for
template conversion functions is not done and only template conversion
functions or non-specialization conversion functions are found:

struct A {
template<typename T> operator int(); // #1
template<typename T> operator T(); // #2
operator int(); // #3
};

struct B : A {
// only specifies the name of #1 and #3
using A::eek:perator int;
};

Option 2:
----------

- After determining the meaning of the name, if the name refers to a
template conversion function specialization, the program is ill-formed.

struct A {
template<typename T> operator int(); // #1
template<typename T> operator T(); // #2
operator int(); // #3
};

struct B : A {
// ill-formed, because it refers to a specialization of #2.
using A::eek:perator int;
};

------------------------

Subsequently, i found a note in 7.3.3/4 which indicates the first option is
taken:

"Since specializations of member templates for conversion functions are not
found by name lookup, they are not considered when a using-declaration
specifies a conversion function"

This says what the intent of the standard is, and sort of answers my
question i think. If anyone knows normative wording for it, i would still
like to read about it, though.
 
G

Gennaro Prota

I should correct: You can refer to the template itself in C++03 too, but it
makes rather little sense to write such a conversion function where you can:

struct A { template<typename T> operator int(); };
struct B : A { using A::eek:perator int; };

Valid, but since "T" is nondeduced, the utility of it is very doubtly. C++0x
allows for it to have a default argument...

I haven't checked the standard as thoroughly as this question
would require but, yes, *off-hand* I'd have expected that if the
intended meaning was 1 (first bullet above) they would have used
"shall" or "shall not". Whereas "cannot" is, by strict ISO rules
(see e.g.

<http://anubis.dkuug.dk/JTC1/SC22/WG9/isodir3.pdf>

) to be taken as "there is no possibility of".

But...

a) One wonders what's the point of a "there's no possibility of"
/outside of an explicative note/ if it follows from other
normative parts (if it doesn't follow, then why not using
"shall" or "shall not"?). Where are such normative parts in this
case?

b) Not all people who write the C++ standard seem to be aware of
these (IMHO very fastidious and unsuited) rules. I've certainly
found usages of "may not" to where a prohibition was meant, for
instance (an example from memory: the prohibition to replace the
placement forms of operator new), although the document linked
to above doesn't allow it.
 
J

James Kanze

I guess i'm too fast with pressing "send" with non-moderated
groups :) Here is what i sent to comp.std.c++, which is more
what i meant to write. Please forgive my many
follow-self-answers. I'm really a bloody usenet-
nonmoderated-groups starter:

I see two interpretations:
Option 1:
----------
- During determining the meaning of the name, argument deduction for
template conversion functions is not done and only template conversion
functions or non-specialization conversion functions are found:
struct A {
template<typename T> operator int(); // #1
template<typename T> operator T(); // #2
operator int(); // #3

Note that these are three, unrelated overloaded functions.
struct B : A {
// only specifies the name of #1 and #3
using A::eek:perator int;

According to my understanding of what you've posted, #1 will not
be found, and this only specified #3.

Note that #1 requires very special syntax to be used anyway.
Since there is nothing in the declaration which depends on the
template type, type deduction will always fail on it, and the
only way to call it is:
int x = anA.operator int said:
Option 2:
----------
- After determining the meaning of the name, if the name refers to a
template conversion function specialization, the program is ill-formed.
struct A {
template<typename T> operator int(); // #1
template<typename T> operator T(); // #2
operator int(); // #3
};
struct B : A {
// ill-formed, because it refers to a specialization of #2.
using A::eek:perator int;

Not ill-formed, because it refers to #3.
};

Subsequently, i found a note in 7.3.3/4 which indicates the
first option is taken:
"Since specializations of member templates for conversion
functions are not found by name lookup, they are not
considered when a using-declaration specifies a conversion
function"
This says what the intent of the standard is, and sort of
answers my question i think. If anyone knows normative wording
for it, i would still like to read about it, though.

I'm still trying to understand the question. But one thing is
certain:
int x = anA;
will, without any further qualifications, invoke #3. And this
is what I would intuitively expect using A::eek:perator int to
refer to.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top