This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: libstdc++ not conforming with --enable-concepts-check?
On Wed, Sep 22, 2004 at 04:35:40PM +0200, Paolo Carlini wrote:
> magfr@lysator.liu.se wrote:
>
> >Hello.
> >
> >If I try to compile the attached program and have built the compiler with
> >--enable-concept-checks that fails but as far as I can see from the
> >standard
> >queue only requires that the elements should be CopyConstructible, there is
> >no requirement for DefaultConstructability, so I think that is a bug in the
> >concept checking code.
> >
> Hi and thanks for your message: in my opinion, indeed, we have a bug.
>
> The problem is tha we are enforcing a wrong requirement for sequences:
> compare
> Table 67 with:
>
> template <class _Sequence>
> struct _SequenceConcept
> {
> typedef typename _Sequence::reference _Reference;
> typedef typename _Sequence::const_reference _Const_reference;
>
> void __constraints() {
> // Matt Austern's book puts DefaultConstructible here, the C++
> // standard places it in Container
> // function_requires< DefaultConstructible<Sequence> >();
> __function_requires< _Mutable_ForwardContainerConcept<_Sequence> >();
> __function_requires< _DefaultConstructibleConcept<_Sequence> >();
>
> _Sequence
> __c _IsUnused(__n), // line 730
> __c2 _IsUnused(__n, __t),
> __c3 _IsUnused(__first, __last);
> ...
> ...
> ...
>
> The requirement enforced at line 730 is not present in Table 67 (*).
Note that Austern does say that a Sequence has a Fill Ctor (called a
Default Fill Ctor in the SGI docs), X(n), which does require X::value_type
to be DefaultConstructible.
The standard combines that function with the (non-default) Fill Ctor so
the value_type only needs to be DefaultConstructible if the default
value is used for the value_type argument.
As allowed by the standard, libstdc++ sometimes implements that fill ctor
as two functions, with/without the default-able argument.
e.g. in std::deque ...
deque(size_type __n, const value_type& __value,
const allocator_type& __a = allocator_type())
: _Base(__a, __n)
{ _M_fill_initialize(__value); }
explicit
deque(size_type __n)
: _Base(allocator_type(), __n)
{ _M_fill_initialize(value_type()); }
The second of these functions _does_ require value_type to be
DefaultConstructible, so an explicit instantiation of e.g.
std::deque<NonDefaultConstructible> fails.
But I was surprised to find that in debug mode it doesn't fail.
i.e. this is a case where the debug mode _allows_ code that non-debug
mode rejects!
#include <deque>
struct NonDefaultConstructible
{
NonDefaultConstructible(int) { }
};
namespace std
{
template class deque<NonDefaultConstructible>;
}
This compiles fine in debug mode.
Splitting the __gnu_debug::deque fill ctor into two functions (as is
done with std::deque) causes the debug mode container to fail as
expected.
So, some questions.
1) Is that explicit instantiation _required_ to fail, or is it a
consequence of splitting the constructor into several functions?
2) If it must fail, is this worth fixing in the debug mode?
It would mean changing all __gnu_debug::containers to exactly match
the constructors of the std::containers they wrap.
3) If it isn't required to fail, does that mean the testcase above is
implementation-defined behaviour, since it depends on whether the
implementation defines the constructors exactly as given in the
standard or as multiple functions? Is that intended?
jon
--
"You know how dumb the average guy is?
Well, mathematically, by definition,
half of them are even dumber than that."
- J.R. "Bob" Dobbs