Boost logo

Boost :

From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2002-11-20 17:21:55


----- Original Message -----
From: "Douglas Gregor" <gregod_at_[hidden]>

> > This isn't what that section means however. It is only a list a few
cases
> > of "trying to form any type that isn't a C++ type."
>
> ... but I've stated what was the intent of the committee (according to my
> recollection from talking with Daveed); that is, to fail when one tries to
> form a type that isn't a C++ type. Do you have any specific cases they
have
> missed? If so, then there is a defect and we should report it. Note that
> sizeof()-based cases (that rely on semantic checks) don't apply, because
they
> aren't based on forming new types and should cause a real error (not
template
> argument deduction failure).

Given the intent of the committee on this issue, then yes, it should cause a
real error rather than failure. What I want to know is *why* that is
considered a good resolution. I see no gain an any way for type deduction
failure to fail only in this regard.

> > I'm talking about the strict interpretation of the standard
(14.8.3)--not
> > what current compilers do. Type deduction happens *before* overload
> > resolution--i.e. in the process or building a candidate set. The
template
> > function just has to be visible. So, in order for the function to
"never
> > make it into the overload set," it has to fail type deduction (i.e. not
> > pass and _not_ error).
>
> There's a _huge_ miscommunication here. I'm talking about your proposed
> resolution, and assuming that we adopt the rule "template argument
deduction
> fails if the result is a semantically invalid declaration". One can then
> write a function template whose declaration will _always_ be ill-formed,
so
> it will never succeed at template argument deduction.

I'm only talking about things that a dependant on template parameters.
Something like this would be a compile-time error just by passing the
declaration:

template<class T> void f(T&*);

That is not what I mean. Type deduction can fail only if the declaration
was previously passed without error. Otherwise, type deduction on the given
template function and overload resolution in general is moot.

Besides, you'd actually have to go out of your way to concoct a declaration
that would *always* be ill-formed when instantiated with template arguments.
And even if you did, so what? You can write an overload that will never be
selected already:

class x {
    private:
        struct y { };
    friend void f(y);
};

void f(x::y) { }

You can even write a template function declaration that will _never_ pass
type deduction already.

> How will the user get
> an error when trying to call this function? (Answer: use a C++98 compiler,
> which will emit an error on any attempt to instantiate the function
template
> declaration).

What kind of function declaration are you talking about here? I'm only
talking about declarations that aren't ill-formed all by themselves--without
any instantiation whatsoever.

> The issue I have is that your resolution may make it easier to write code
that
> "compiles", but only because the definition is never actually
instantiated.
> And when it's easier to write bad code that the compiler won't catch, it's
> harder to learn the language.

If you're running into problems caused by type deduction failure, then you
already should be pretty solid on the language itself. It wouldn't exactly
be surprising that a template function was not selected if it was invalid
with a given template argument. Plus, I can just as easily make the case
that the reverse is true--that having a specific list of "failures" is more
complex for one learning the language.

> > This isn't a case of a "badly broken function template," nor is a case
of
> > it being "silently useless." It can be a perfectly worthwhile function
> > template.
>
> Do you have a concrete example? This would help us greatly.

I already gave several. In particular, how about
pointer-to-member-reference:

struct X { };

template<class T> void f(T X::*);
template<class T> void f(T x, T y);

f<int&>(0, 0); // error in type deduction of function
               // that never would be selected anyway

> > This change would do several things,
> > 1) cleanup that section of the standard,
>
> "Cleanup" is not a good word to use when we're talking about a change in
> semantics. Cleanup can refer to adding missing cases, introducing
rationale,
> or tighening up the wording in accordance with the intent of the section.

I'm specifically *not* talking about a change in semantics. This whole idea
of a compile-time error during type deduction is not specified *anywhere* in
the standard. In fact, this whole area is *way* underspecified. Even if
you assume that is implied--which I'll grant is possible--all this would do
is make something legal that wasn't before. That isn't "changing
semantics."

Why is the intent as limited as it is? I've yet to hear anyone answer that
question.

> > 2) unify the rules with
> > declaration instantiation ala member functions,
>
> I'm not sure what you mean by this.

I'm referring to declarations of member functions of template classes. In
this case, the compiler already has to detect any member declaration that is
semantically invalid when it instantiates the template class itself. This
is a simple rule, and one that should be followed with type deduction as
well--except with failure rather than an error.

> > 3) give us a huge set of tools to work with for generic programming, and
>
> If we're going to be changing semantics, why not introduce new tools that
> support our goals better?

Oh, we definitely should. :) However, there is no way that we are going to
get all the tools we will possibly need.

> > 4) close a potentially
> > serious hole in the C++ overload mechanism. What this change *wouldn't*
do
> > is alter the results on overload resolution in any way, nor would it
allow
> > more functions into the candidate set.
>
> I don't understand this at all. Where is the hole in the C++ overload
> mechanism? We're only talking about template argument deduction, which is
not
> overloading.

No, but it is part of overloading in the sense that type deduction _must_
happen to produce the overload candidate set. One declaration can
potentially break the entire overload set--even if it is unrelated--which
one of the fundamental purposes of overloading in the first place. This
especially comes into play when Koenig lookup is involved.

> > > ... but don't forget that once we get more language primitives, that
will
> > > enable new tricks as well.
> >
> > Yes. My point is that whatever gets added to 0x is not going to solve
all
> > of our needs. We should never throw away worthwhile tools--even if some
of
> > them make us bend over backward to accomplish something (i.e. the sizeof
> > hack).
> >
> > Paul Mensonides
>
> We don't have this tool now, so there is nothing to throw away.

We don't _not_ have this tool either. The standard doesn't specify either
way, regardless of intent. The standard does not say there is any
possibility of error in type deduction, nor is the *complete* list of
possible failures present in that list. For example, 14.8.2.3/3 says, "If
they yield more than one possible deduced A, the type deduction fails."
Furthermore, 14.8.2/2 (3rd bullet)--"If a substitution in a template
parameter or in the function type of a the function template results in an
invalid type, type deduction fails." What is this...

template<std::size_t> struct X { };

X<sizeof(void)> // ?

...if not an invalid type?

> Doug
>
> [This is getting way off-topic for Boost. We should take this off-line or
over
> to clc++m)

I'm done anyway. I've already made my case. I just think that type
deduction causing an error is ridiculous and unpolished.

Paul Mensonides


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk