numeric_limits<Abstract> or how to fix 1358600?

I commited the fix for 1358600 - lexical_cast & pure virtual functions & VC 8 STL (http://tinyurl.com/yvowz6) for VC++ only but later I found that Intel 8.1 and Comeau online don't compile as well. The problem appears in numeric_limits functions. In this usecase, they return an abstract class by value. Although lexical_cast never uses those functions, it seems that some compilers do more strick checking than I thought they should. For example, class A { public: virtual void foo() = 0; }; template<class T> struct limits { static int const value = true; static T declared_only(); }; int main() { limits<A>::value; } fails to compile on VC++ 8, Intel 8.1 and Comeau online at the point of the declared_only declaration. However, if I replace a body of A with a declaration (class A;), those compilers don't complain anymore. What is this, a compiler bug or my misunderstanding? I remember that some freedom compiling template code is allowed (and therefore, some compiler compiles while some others don't) but I don't know where to search in the standard. -- Alexander Nasonov http://nasonov.blogspot.com The wise man does at once what the fool does finally. -- Baltasar Gracian -- This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$/ --/' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote

Even more, they won't compile it with that limits template: template<class T> struct limits { static int const value = true; typedef T(*declare_type_only)(void); };

Hello Alexander, Saturday, January 20, 2007, 12:22:35 AM, you wrote:
I commited the fix for 1358600 - lexical_cast & pure virtual functions & VC 8 STL (http://tinyurl.com/yvowz6) for VC++ only but later I found that Intel 8.1 and Comeau online don't compile as well.
The problem appears in numeric_limits functions. In this usecase, they return an abstract class by value. Although lexical_cast never uses those functions, it seems that some compilers do more strick checking than I thought they should.
For example,
class A { public: virtual void foo() = 0; };
template<class T> struct limits { static int const value = true; static T declared_only(); };
int main() { limits<A>::value; }
fails to compile on VC++ 8, Intel 8.1 and Comeau online at the point of the declared_only declaration.
However, if I replace a body of A with a declaration (class A;), those compilers don't complain anymore. What is this, a compiler bug or my misunderstanding? I remember that some freedom compiling template code is allowed (and therefore, some compiler compiles while some others don't) but I don't know where to search in the standard.
According to 14.7.1 (namely 14.7.1/2 and 14.7.1/3) the declared_only member should not be instantiated unless it is used somewhere in the code. So I see no reason a compiler to want T to be not abstract. Looks like compiler bug to me. -- Best regards, Andrey mailto:andysem@mail.ru

Andrey Semashev wrote:
According to 14.7.1 (namely 14.7.1/2 and 14.7.1/3) the declared_only member should not be instantiated unless it is used somewhere in the code. So I see no reason a compiler to want T to be not abstract. Looks like compiler bug to me.
Yes, I came across this too. BTW, I just commited another fix that uses is_abstract on all compilers where it is available (BOOST_NO_IS_ABSTRACT). -- Alexander Nasonov http://nasonov.blogspot.com Accept the challenges so that you can feel the exhilaration of victory. -- George Patton -- This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$/ --/' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote

Hello Alexander, Saturday, January 20, 2007, 4:30:49 PM, you wrote:
Andrey Semashev wrote:
According to 14.7.1 (namely 14.7.1/2 and 14.7.1/3) the declared_only member should not be instantiated unless it is used somewhere in the code. So I see no reason a compiler to want T to be not abstract. Looks like compiler bug to me.
Yes, I came across this too. BTW, I just commited another fix that uses is_abstract on all compilers where it is available (BOOST_NO_IS_ABSTRACT).
Ok. It would be nice if you write to MS about that issue with the compiler. Your code might be used to reproduce the problem. -- Best regards, Andrey mailto:andysem@mail.ru

I think it's not a bug, for example comeau doesn't compile this: template<int x> class C { typedef char arr[x]; }; C<0> c; Which is almost the same: class "uses" the type that isn't valid (or there are some words in standard about this case?) So the problem is not that compiler does instantiate member (btw, maybe it doesn't try to), it's that member has illegal type.

And here goes workaround: Wrap invalid type into another template. So that type can't be detected until helper is instantiated. class A { public: virtual void foo() = 0; }; template<class T> class limits_static_functor_helper; //should have public T operator() const template<class T> struct limits { static int const value = true; // static T declared_only(); typedef limits_static_functor_helper<T> declared_only; }; int main() { limits<A>::value; } P.S. maybe it should be not typedef but static member (both works ok), or functor should have static member, instead of non-static operator. It all depend on perfomance, usage, and so on (just i haven't used limits.hpp before :) )

Dmitry Ivankov wrote:
And here goes workaround: Wrap invalid type into another template. So that type can't be detected until helper is instantiated.
[ ... ]
template<class T> struct limits { static int const value = true; // static T declared_only(); typedef limits_static_functor_helper<T> declared_only; };
It won't work for std::numeric_limits because it can't be changed. -- Alexander Nasonov http://nasonov.blogspot.com I love acting. It is so much more real than life. -- Oscar Wilde -- This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$/ --/' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote

Hmm, maybe std::numeric_limits isn't specialized for classes? In that case it's possible to use it only for non-classes. Looks like that 18.2.1/1 and 18.2.1/4 states that numeric_limits is only for fundamental types. So maybe just fix lexical_cast so that it won't use std::numeric_limits for classes?

Dmitry Ivankov wrote:
Hmm, maybe std::numeric_limits isn't specialized for classes? In that case it's possible to use it only for non-classes.
Looks like that 18.2.1/1 and 18.2.1/4 states that numeric_limits is only for fundamental types.
So maybe just fix lexical_cast so that it won't use std::numeric_limits for classes?
numeric_limits *can* be specialised for user defined types, and IMO lexical_cast should use the information. If the only issue is abstract types, can't we simply filter out abstract types before invoking numeric_limits? Note that on compilers that don't support is_abstract fully the class defaults to the same behaviour as is_polymorphic, and while that may then filter out some classes that shouldn't be on broken compilers, it's a quite reasonable compromise. John.

Good idea. What about a backdoor for those compilers? Something like let users specialize i_really_have_specialized_numeric_limits<T>::value for their non-abstract polymorphic types. Or even write a replacement for not very reliable std::numeric_limits<T>::is_specialized Something like numeric_limits_is_specialized<T>::value = #ifdef BOOST_NO_IS_ABSTRACT i_really_have_specialized_numeric_limits<T>::value || #endif !is_abstract<T>::value && std::numeric_limits<T>::is_specialized

Dmitry Ivankov wrote:
Good idea. What about a backdoor for those compilers? Something like let users specialize i_really_have_specialized_numeric_limits<T>::value for their non-abstract polymorphic types.
I don't think that it's necessary to be that complicated: 1) If the type *is* really abstract, then numeric_limits support probably doesn't make sense since the type is not a "value" type. So filtering out abstract types probably makes sense whatever. 2) If a type is *not* abstract and the compiler supports numeric_limits then we're OK anyway I think? 3) If the compiler is broken and doesn't support is_abstract, then users can always specialise is_abstract for a non-abstract polymorphic type if they want the numeric limits code to kick in. John.

John Maddock wrote:
I don't think that it's necessary to be that complicated:
1) If the type *is* really abstract, then numeric_limits support probably doesn't make sense since the type is not a "value" type. So filtering out abstract types probably makes sense whatever.
2) If a type is *not* abstract and the compiler supports numeric_limits then we're OK anyway I think?
Exactly this reasoning drove me to the current fix.
3) If the compiler is broken and doesn't support is_abstract, then users can always specialise is_abstract for a non-abstract polymorphic type if they want the numeric limits code to kick in.
In this situation, I decided to use numeric_limits. As I wrote in other post, we'll see how it works. If it doesn't work well, we can switch to your proposal and update compatibility section of the docs. -- Alexander Nasonov http://nasonov.blogspot.com Chicago sounds rough to the maker of verse. One comfort we have: Cincinnati sounds worse. -- Oliver Wendell Holmes -- This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$/ --/' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote

John Maddock wrote:
If the only issue is abstract types, can't we simply filter out abstract types before invoking numeric_limits? Note that on compilers that don't support is_abstract fully the class defaults to the same behaviour as is_polymorphic, and while that may then filter out some classes that shouldn't be on broken compilers, it's a quite reasonable compromise.
That's what I did except that I never use is_polymorphic. Instead, I rely on numeric_limits not complaining about abstract type. We'll see how it goes when automated regression tests turn their attention to HEAD and particularly to ./libs/conversion/test/lexical_cast_abstract_test.cpp. Colored diff: http://tinyurl.com/2rwg8r The reason I asked this question was a possibility of similar failures. For example, abstract class could be replaced with noncopyable class. But all compilers I tried don't complain about noncopyable classes in numeric_limits. Though, I don't know what is a difference between these two kind of classes. Anyway, I added ./libs/conversion/test/lexical_cast_noncopyable_test.cpp. -- Alexander Nasonov http://nasonov.blogspot.com Good judgment comes from experience. Experience comes from bad judgment. -- Jim Horning -- This quote is generated by: /usr/pkg/bin/curl -L http://tinyurl.com/veusy \ | sed -e 's/^document\.write(.//' -e 's/.);$/ --/' \ -e 's/<[^>]*>//g' -e 's/^More quotes from //' \ | fmt | tee ~/.signature-quote

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Dmitry Ivankov Sent: 21 January 2007 12:12 To: boost@lists.boost.org Subject: Re: [boost] numeric_limits<Abstract> or how to fix 1358600?
Hmm, maybe std::numeric_limits isn't specialized for classes?
In that case it's possible to use it only for non-classes. Looks like that 18.2.1/1 and 18.2.1/4 states that numeric_limits is only for fundamental types.
So maybe just fix lexical_cast so that it won't use std::numeric_limits for classes?
I think you are misunderstanding 18.2.1/1 (though I admit it is not as clear as it might be in what is permitted and what is explicitly NOT specialized - complex<T> in 18.2.1.4) - std::numeric_limits is used in practice for all classes, including user-defined types - but entries are 'blank' (zero) unless specialized. lexical_cast is expressly designed to take account of whether the User-defined class is specialized, or not. Paul --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com
participants (5)
-
Alexander Nasonov
-
Andrey Semashev
-
Dmitry Ivankov
-
John Maddock
-
Paul A Bristow