3

C++ STL containers don't allow instantiation with incomplete types; it is undefined behavior.

Is this a valid "trick" to get around that restriction? Or does this trick still have undefined behavior?

#include <vector>

template<template<class, class> class Vector = std::vector>
struct my_incomplete_vector
{
    struct Element;

    // Element is incomplete here, but does it matter anymore?
    typedef Vector<Element, std::allocator<Element> > type;

    struct Element { typename type::iterator value; };
};

int main()
{
    my_incomplete_vector<>::type v;
    v.resize(1);

    // this isn't normally possible without incomplete types
    v[0].value = v.begin();
    return 0;
}
user541686
  • 205,094
  • 128
  • 528
  • 886

1 Answers1

4

It's undefined behavior. The standard requires a type to be complete if it is used as the argument of a template, at the point where the template is instantiated. And my_incomplete_vector::Element is not complete when you use it inside Element. No problems will occur until you actually instantiate your template, of course, but g++ fails to compile your code with the usual debugging options (-D_GLIBCXX_CONCEPT_CHECKS -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC).

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Isn't this is similiar to `struct T { T * p;}`? `T` is not complete but is OK to define a pointer/iterator? – CS Pei Sep 26 '13 at 17:36
  • @JohnSmith a type doesn't have to be complete to have a pointer to it declared. – Adam Maras Sep 26 '13 at 17:46
  • @JohnSmith No. `struct T { T* p; }` has nothing to do with the requirements on a template argument. In order to declare a variable of type `type::iterator`, `type` must be instantiated. And the standard says that when a template is instantiated, the type is is instantiated over must be complete (with a couple of exceptions). I don't see any relationship with pointers. – James Kanze Sep 26 '13 at 18:13
  • 1
    @JamesKanze: I don't understand what exactly is undefined here though. At the point of instantiation of `vector`, `Element` is already defined, isn't it? When is `vector` instantiated with an incomplete `Element` type? – user541686 Sep 26 '13 at 18:22
  • @JohnSmith: For any object type `T`, `T*` is a complete type. – Kerrek SB Sep 26 '13 at 19:39
  • @Mehrdad: FWIW, VS 2012 (VC++11) compiles it just fine. – ForeverLearning Sep 26 '13 at 20:41
  • @Dilip: Yup that's where I originally tested it. – user541686 Sep 27 '13 at 01:35
  • 1
    @Mehrdad No. The point of instantiation of `vector` is inside the class `Element`, so `Element` is still an incomplete type. – James Kanze Sep 27 '13 at 08:24
  • 1
    @Dilip Which is one possible result of undefined behavior. The committee wanted to require a diagnostic for this in C++11, but this depended on concepts, which for various reasons didn't get in. – James Kanze Sep 27 '13 at 08:27