Re: container traits
Greg Herlihy wrote:
kanze wrote:
Jens Theisen wrote:
Greg Herlihy wrote:
Both compilers should accept this code - there is nothing
undefined about it at all. The tlist_iterator typedef is
neither an explicit instantiation nor a specialization of
std::list::iterator
Do you know where the requirement of list being instantiable
with incomplete T is in the standard? It should be somewhere.
?17.4.3.6/2: "In particular, the effects are undefined in the
following cases: [...] -- if an incomplete type is used as a
template arugment when instantiating a template component."
Declaring an empty, derived class of T would be an obvious
"workaround".
For what? The standard (?14.7.1/4) explicitly says that "A
class template specialization is implicitly instantiated if the
class type is uned in a context that requires a
completely-defined object type or if the completeness of the
class type affects the semantics of the program; [...]" If you
derive from a template specialization, the specialization will
be instantiated.
There is no question that T is complete in the program below.
But it should just as clear that the program's behavior is
indistinguishable from the original.
Why?
After all, a program's behavior is affected soley by the
instructions it executes and the data it processes.
I'd say that it could also be affected by whether the program
compiles or not. A program with undefined behavior has just
that, undefined behavior. The compiler might not compile it, or
it might generate different instructions. The standard makes no
requirements. (In the case in question, of course, it seems a
rather safe bet that if the code compiles, it will work.)
Instantiating std::list<T> (or any template class) creates
neither code nor data. And there cannot be undefined behavior
when there is no behavior at all.
What makes you say that? The standard says that instantiating a
standard template with an incomplete class is undefined
behavior. Even if instantiating a class (as opposed to
instantiating the members of the class) does not necessarily
generate code or data, the standard signals other reasons why
the definition is necessary.
#include <list>
struct T { int x; };
template <class Type>
struct SelfIter : public Type
{
SelfIter() : Type() {}
typename std::list<Type>::iterator mIterator;
};
int main()
{
SelfIter<T> ti;
std::list<T> tList;
// insert ti in list while storing its iterator
ti.mIterator = tList.insert( tList.begin(), ti);
}
The code you posted is illegal, and at least one
compiler/library implemenation rejects it.
I would note that gcc's -D_GLIBCXX_CONCEPT_CHECK will reject
any program that so much as declares a std::list<T>.
Have you actually tried it? I has no problems with the following
(legal) program:
#include <list>
class T ;
typedef std::list< T > ListT ;
extern void f( ListT& ) ;
The key is whether a complete type is needed or not. In this
code, there is no place where a complete type is needed, so the
template specialization isn't instantiated, and there is no
problem. Derive from std::list<T>, or use it on the left side
of a :: operator, and a complete type is needed, the compiler
instantiates the template, and g++ complains, because the
standard says that you have undefined behavior.
A concept check tests a template class for its completeness -
it does not test a program for its correctness.
I don't think you understand the concept checking done by g++
(which derives from that developped by Boost).
I've cut the rest, because your descriptions bear no resemblance
to what g++ does in its concept checking.
In fact, a concept check essentially does nothing more than
declare a complete, explicit instantiation of std::list<T>
like so:
template class std::list<T>;
This is simply false. The concept checking in g++ verifies a
lot of things: it insists, for example, that T be assignable,
even though the implementation of std::list in g++ never uses
assignment. It does NOT force a complete instantiation of the
class; the only instantiations you get are those that you would
normally get.
and with the same, predictable results. As a test, a concept
check is useful (and is in fact intended only for) a person
actually writing a template class library.
The concept check is designed for people using the class
library, not for those writing it. It is designed to ensure
that you fulfil the contractual obligations, even if the actual
generated code doesn't require them. It requires that the
instantiation type of std::list support assignment, for example,
although the g++ implementation (and I suspect most others) of
std::list never uses it. Because the standard says that the
contained type of ALL standard containers must support
assignment, even if it isn't technically necessary for
std::list.
For any other type of programming, the types of "failures"
reported - such as the fact that T does not implement either a
< or a == operator are simply not relevant.
And are not reported, unless you use a function which requires
them. I don't know where you got your information about concept
checking, but it certainly doesn't come from using the g++
implementation.
A program that never compares or sorts T objects and never
calls any method in std::list that does - has no reason (and
certainly no obligation) to overload those operators in T.
A program that never calls a function in std::list<T> which
contractually requires a < operator will not fail the concept
checks. A program that calls, say, std::list<T>::sort will fail
to compile if it doesn't define an operator< for T. In this
particular case, concept checks aren't even necessary, and
change nothing.
--
James Kanze GABI Software
Conseils en informatique orient9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S9mard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34
---
[ 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.comeaucomputing.com/csc/faq.html ]