Topic: Should failure to instantiate a function template abort compilation
Author: chris jefferson <caj@cs.york.ac.uk>
Date: 10 Aug 2005 17:30:01 GMT Raw View
Gianluca Silvestri wrote:
> "Howard Hinnant" <hinnant@metrowerks.com> ha scritto nel messaggio
> news:hinnant-7A2DC8.09274510082005@syrcnyrdrs-03-ge0.nyroc.rr.com...
> | In article <1123642375.849913.19940@f14g2000cwb.googlegroups.com>,
> | "Wu Yongwei" <wuyongwei@gmail.com> wrote:
> |
> | > My current opinion is that failure to instantiate a template function
> | > should automatically remove it from the candidates of overload
> | > resolution.
> |
> | Compiler writers are understandably apprehensive of being required to
> | back out of an arbitrarily complex function which generates an error.
> | By "back out", I mean the compiler would have to put itself in the exact
> | same state as it had before it began the function instantiation. I'm
> | not saying it is impossible to do so, just that this would be a new and
> | non-trivial requirement on the compiler.
> |
>
> What about keeping in the overload set those function templates that now
> cause a compile error , mark them in some way and proceed with overload
> resolution. If one of them win the match then the compiler issue an error,
> otherwise the best one is chosen.
>
Not being insulting, but what you suggest is of course a simple overview
of how any implementation of this would have to work. I am but an
amateur in the field of writing C++ compilers (I'm trying to slowly
understand g++), but I can see that what is being asked for is very
complex. If Howard Hinnant tells you something is hard, you are highly
unlikely to come up with a cunning means of solving it in a paragraph
and 30 seconds thought :)
Also, I imagine some people (including myself) might be causious about
exactly what "failure to instantiate" would cover. For example, consider
that I meant to write iterator_traits<T>::value_type in a
specialisation, but I accidentally wrote iterator_traits<T>::valuetype
instead. It might be very hard to spot this problem, as the compiler
would simply try to instansiate the function, fail, and carry on and do
the less optimized version (yes of course, there are already ways you
can slip up in similar ways, but they are limited (I believe) purely to
the definition of functions / classes).
Chris
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: caj@cs.york.ac.uk (chris jefferson)
Date: Thu, 11 Aug 2005 05:24:09 GMT Raw View
Howard Hinnant wrote:
> In article <1123485075.096196.242990@g44g2000cwa.googlegroups.com>,
> wuyongwei@gmail.com wrote:
>
>
>>The discussion in comp.lang.c++.moderated:
>>
>>http://groups-beta.google.com/group/comp.lang.c++.moderated/browse_thread/thre
>>ad/3c449572456c8592
>>
>>Paul Mensonides's post seems decisive. However, this failure is ugly,
>>counter-intuitive, and user-unfriendly (not to mention that the error
>>messages I have seen are all very confusing since they say everything
>>unrelated to the user's code). Anyone knows of anything improved in
>>this aspect?
>
>
> CodeWarrior is experimenting with an enable_if-like return type on
> std::distance so that this overload will not participate in overload
> resolution if InputIterator isn't an iterator. Your example on our
> implementation will compile and set d == 2 at runtime.
>
I had thought about using a similar technique on many other of the
functions in std::, for example to stop functions matching if they are
given incorrect iterator types, which should hopefully lead to better
(or at least much smaller) error messages. However I was under the
impression that all functions had to have exactly the same signiture as
they do in the standard? Am I wrong?
Chris
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: richard_corden@hotmail.com (Richard Corden)
Date: Thu, 11 Aug 2005 14:47:08 GMT Raw View
Gene Bushuyev wrote:
[...]
> // --- almost c++ code for compiler ---
>
> Function overload_resolution(function_name, arguments)
> {
> set<Function> overload_set;
> set<Function> failed_set;
> for(Function function = parse_tree.functions.begin();
> function != parse_tree.functions.end(); ++function)
> if(function->name == function_name
> && function->check_lookup_rules())
> {
> if(function->is_a_template()
> {
> try
> {
> if(! function->is_explicitly_specialized())
> template_arguments =
> function->deduce_template_arguments(arguments); //
> 14.8.2
> instance = function->instantiate(template_arguments) //
> 14.7.1
> overload_set.insert(instance); // 14.8.3/1
> }
> catch(...)
> {
> failed_set.insert(*function); // only for reporting purposes
> // do nothing with this candidate according to 14.8.3/1
> }
> }
> else
> overload_set.insert(*function);
> }
[...]
The try catch is not quite correct - as you are missing when the
function type needed a class template body to be instantiated.
Function Function::instantiate (TemplateArguments)
throw (DeductionFailure, NonDeductionFailure);
And then the catch would be:
catch (DeductionFailure const &)
{
failed_set.insert(*function); // only for reporting purposes
// do nothing with this candidate according to 14.8.3/1
}
Regards,
Richard
--
Richard Corden
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: richard_corden@hotmail.com (Richard Corden)
Date: Thu, 11 Aug 2005 17:11:12 GMT Raw View
Richard Corden wrote:
>
> Gene Bushuyev wrote:
>
[...]
>
> The try catch is not quite correct - as you are missing when the
> function type needed a class template body to be instantiated.
>
> Function Function::instantiate (TemplateArguments)
> throw (DeductionFailure, NonDeductionFailure);
>
>
> And then the catch would be:
>
> catch (DeductionFailure const &)
> {
> failed_set.insert(*function); // only for reporting purposes
> // do nothing with this candidate according to 14.8.3/1
> }
>
I should add that if 'NonDeductionFailure' is thrown, it will be caught
somewhere above where the compiler then immediately issues an error.
Richard
--
Richard Corden
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: richard_corden@hotmail.com (Richard Corden)
Date: Thu, 11 Aug 2005 18:49:29 GMT Raw View
Hi,
Pavel Kuznetsov wrote:
> Richard,
>
[...]
>>
>> template <typename T>
>> typename A<T>::TYPE foo (T); // Does not use SFNAE
[...]
>
> I fail to see why you're saying that SFINAE does not take place in
> the second case, and in fact the standard contains a similar example:
>
> 14.8.2/2 <...> Type deduction may fail for the following reasons:
> <...>
> - Attempting to use a type in the qualifier portion of a qualified
> name that names a type when that type does not contain the
> specified member, or if the specified member is not a type where
> a type is required. [Example:
> template <class T> int f(typename T::B*);
As your testing points out, I had neglected to put an error in the
definition of 'A<T>'. Example (this time checked):
template <typename T>
class A
{
typename T::TYPE car (T); // #1
};
template <typename T>
typename A<T>::TYPE foo (T);
template <typename T>
typename T::TYPE foo (T); // #2
void foo (int);
void bar ()
{
foo (0);
}
Although almost identical, SFNAE does not apply during the instantiation
of 'A', so #1 is not covered by SFNAE.
14.8.2/2 does not have a bullet to cover the case where the class fails
to instantiate and since 14.8.2/2 is a list of all the situations where
SFNAE occurs, if its not explicitly listed there then it doesn't happen.
AFAIK it's not an over site of the committee that such a failure is not
listed.
[...]
> This is exactly what Comeau Online and VC++8 beta 2 has to say for your
> example:
[...]
Yes, my example had no failure.
I now realise through my mistake, that the behaviour would not be much
different from today if we allowed instantiation failure to be covered
by SFNAE.
In such a hypothetical world the only consequence is that names might
get added to the enclosing scope based on their position in the class
definition!
template <typename T>
struct A
{
friend void foo (A<T> const &, class X const &);
typename T::TYPE car ();
friend void foo (A<T> const &, class Y const &);
};
Are types 'X' and 'Y' always added to the enclosing scope?
Regards,
Richard
--
Richard Corden
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]