Template problems with typedefs and forward declarations

Template problems with typedefs and forward declarations

imagem de scottdanderson

Hello forum,

I'm engaged in a port of approximately 2M lines of code from Solaris/Win2K to Linux. Currently I'm evaluating compilers, and I'm finding a number of things that compile fine in gcc 3.X and gcc 2.95.X that won't compile with the Intel compiler.

Now, 2.95.x has an exception handling bug that makes it useless. 3.X is sufficiently picky about our C++ code that the porting would take considerably longer. So, I decided to evaluate the Intel compiler (and get the floating point optimizations as well; we use a lot of fp code).

Here's the code that's giving me issues (I've added the two relevant line numbers):

From BDAlloc.h:

template
class CBDCachedAllocator
{
public:
132: typedef T & reference;
...
}

From INIFile.h:

class CINIFile
{

public:
class Section;
typedef CBDCachedAllocator SectionAllocator;
typedef std::list Sections_t;

class Section : public stringnc
{
friend class Section_iter;
friend class std::list;
...
};

113: class Section_iter : public Sections_t::iterator
{
...
}

...}

The error I'm getting is:

BDAlloc.h(132): error: reference to void is not allowed
typedef T & reference;
^
detected during:
instantiation of class "CBDCachedAllocator [with T=void, COUNT=256, SIZE=-1]" at line 17 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::_List_nod<_Ty, _Alloc> [with _Ty=CINIFile::Section, _Alloc=CINIFile::SectionAllocator]" at line 46 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::_List_ptr<_Ty, _Alloc> [with _Ty=CINIFile::Section, _Alloc=CINIFile::SectionAllocator]" at line 66 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::_List_val<_Ty, _Alloc> [with _Ty=CINIFile::Section, _Alloc=CINIFile::SectionAllocator]" at line 83 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::list<_Ty, _Ax> [with _Ty=CINIFile::Section, _Ax=CINIFile::SectionAllocator]" at line 113 of "INIFile.h"

So it appears to me that the Intel compiler doesn't handle forward declarations when used by templates very well, since SectionAllocator sends Section, not void, as T to CBDCachedAllocator. Or, this could be some issue in the Intel STL. I haven't tried it with STLPort yet, as I didn't want to take the time to recompile it first.

Now, I'm not much of a C++ guru (learning as I go), so if this is a newbie error feel free to just say, "figure it out". Unfortunately, it's not my code (I'm just responsible for porting it) and I'd really like to use this compiler if I can (for the optimizations). The more issues like this I have to resolve, the worse off I am. :-/

Thanks in advance,
Scott Anderson

7 posts / 0 new
Último post
Para obter mais informações sobre otimizações de compiladores, consulte Aviso sobre otimizações.
imagem de scottdanderson

This works fine in gcc 3.2.1, gcc 2.95.2/4, and MSVC 6.0:

#include
#include


template
class CTestAlloc
{
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T * pointer;
typedef const T * const_pointer;
typedef T & reference;
typedef const T & const_reference;

template
struct rebind { typedef CTestAlloc other; };
};


class CTest
{
typedef std::string string;

public:
class Field;
class Field_iter;

typedef CTestAlloc FieldAllocator;

typedef std::list Fields_t;

class Field : public string
{
};

class Field_iter : public Fields_t::iterator
{
};

public:
CTest();
virtual ~CTest();
};


Using 'icc -o ./obj/test.o -c test.cpp', I get:

test.cpp(13): error: reference to void is not allowed
typedef T & reference;
^
detected during:
instantiation of class "CTestAlloc [with T=void]" at line 17 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::_List_nod<_Ty, _Alloc> [with _Ty=CTest::Field, _Alloc=CTest::FieldAllocator]" at line 46 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::_List_ptr<_Ty, _Alloc> [with _Ty=CTest::Field, _Alloc=CTest::FieldAllocator]" at line 66 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::_List_val<_Ty, _Alloc> [with _Ty=CTest::Field, _Alloc=CTest::FieldAllocator]" at line 83 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::list<_Ty, _Ax> [with _Ty=CTest::Field, _Ax=CTest::FieldAllocator]" at line 37

test.cpp(14): error: reference to void is not allowed
typedef const T & const_reference;
^
detected during:
instantiation of class "CTestAlloc [with T=void]" at line 17 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::_List_nod<_Ty, _Alloc> [with _Ty=CTest::Field, _Alloc=CTest::FieldAllocator]" at line 46 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::_List_ptr<_Ty, _Alloc> [with _Ty=CTest::Field, _Alloc=CTest::FieldAllocator]" at line 66 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::_List_val<_Ty, _Alloc> [with _Ty=CTest::Field, _Alloc=CTest::FieldAllocator]" at line 83 of "/opt/intel/compiler70/ia32/include/list"
instantiation of class "std::list<_Ty, _Ax> [with _Ty=CTest::Field, _Ax=CTest::FieldAllocator]" at line 37

compilation aborted for test.cpp (code 2)


Is this illegal code, or is this an icc bug?

Thanks,
-scott

imagem de bop2

Unfortunately, Intel's compiler is correct!

You cannot use an incomplete type as a template parameter.

imagem de Jennifer J. (Intel)

The Intel C++ Compiler 7.0 for Windows does compile your second test case like MS.
There's no forward declaration for "struct rebind {}". It is where the compiler complaining. But if gcc can compile, icc should also.

Why not submit a bug through Premier Support? Your testcase is good enough.

Jennifer

imagem de scottdanderson

So this looks like it might be an issue with the Intel STL stuff.

Regards,
-scott

imagem de scottdanderson

In addition to gcc 2.95.2 w/stlport, gcc 3.2.1, and MSVC 6.0.

imagem de Judith Ward (Intel)


I think this is the same problem as reported in
tracker 31742, Q175037. It is due to a difference
in the implementation of the Intel standard library
versus the Gnu standard library.

Here is my explanation and a workaround:

Investigation Note [2/11/2003 7:16:52 PM(joego)]:

Do you think this is a compiler bug exposed by library header code, or a bug in the library header code?


Investigation Note [2/12/2003 8:10:29 AM(jward4)]:


/*
I think this is a bug (i.e. a requirement on users that
is not dictated by the standard) in the library. If you run
the small example below you'll get an error with both
g++ and icc. The problem seems to be that if
the user defines their own allocator and use it
in the list class they also need to provide a specialization of that
allocator for void or else they'll have a problem when the _List_nod class
is instantiated. I looked at the standard in section 20.1.5
and didn't see a void specialization listed as an Allocator requirement.
It could be that Bill will think that this a defect in the
standard, I'd ask him about it.

It probably wouldn't hurt though for the user to add one.
The generic allocator class has one, so if they add:

// specialization of user's allocator on void
// this mimics the generic allocator specialization
// add this after the CTestAlloc template declaration
template <>
struct CTestAlloc
{
public:
typedef void* pointer;
typedef const void* const_pointer;
// reference-to-void members are impossible
typedef void value_type;
template
struct rebind { typedef CTestAlloc other; };
};

then their example will work fine.
*/

// Reduced code from Dinkumware library
template class allocator{};

template
class _List_nod
{
typedef typename _Alloc::template
rebind::other::pointer _Genptr;
struct _Node {};
};


template
class _List_ptr : public _List_nod<_Ty, _Alloc>
{
typedef typename _List_nod<_Ty, _Alloc>::_Node _Node;
};


template
class _List_val : public _List_ptr<_Ty, _Alloc> {};


template >
struct list : public _List_val<_Ty, _Ax>
{
class const_iterator {};
};

// user's code
template
struct CTestAlloc
{
typedef T value_type;
typedef T * pointer;
typedef const T * const_pointer;
typedef T & reference;
typedef const T & const_reference;
template
struct rebind { typedef CTestAlloc other; };
};


struct CTest
{
typedef CTestAlloc FieldAllocator;
typedef list Fields_t;
Fields_t::const_iterator i;
};



Workaround [2/12/2003 8:12:00 AM(jward4)]:


Add this specialization for the CTestAlloc class:

// specialization of user's allocator on void
// this mimics the generic allocator specialization
// add this after the CTestAlloc template declaration
template <>
struct CTestAlloc
{
public:
typedef void* pointer;
typedef const void* const_pointer;
// reference-to-void members are impossible
typedef void value_type;
te
mplate
struct rebind { typedef CTestAlloc other; };
};

Faça login para deixar um comentário.