Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.

Bug with typedef

asd__asdqwe
Beginner
351 Views

Hello,

First of all, sorry for this report, it looks like a nasty bug and I can't give you a simple reproducer (closed source and stripped-down example just works fine).

I'm performing the following calls on a highly templated with many inheritance code:

[cpp]size += static_cast<std::vector<pairN>>(_ref.A::_map).second.size();
size += _ref.A::_map.second.size();[/cpp]

The first line compiles fine, the second does not, with the following error message:

error: no operator "[]" matches these operands
operand types are: const vectorN [ unsigned short ]
size += _ref.A::_map.second.size();

With [cpp]typedef std::pair<unsigned short, std::vector<int>> pairN; typedef std::vector<pairN> vectorN;[/cpp]

Of course, I don't have any problem with clang++ or g++. Any ideas ? Why on earth should I have to cast _ref.A::_map to its own type ?

Thank you.

0 Kudos
4 Replies
asd__asdqwe
Beginner
351 Views

Still can't edit the first post it appears ... Here is a reproducer:

[cpp]

#include <vector>

typedef std::pair<unsigned short, std::vector<int>> pairN;
typedef std::vector<pairN> vectorN;

template<class T>
class FooBase {
protected:
const T& _ref;
public:
FooBase(const T& ref) : _ref(ref) { };
};

class Bar {
protected:
vectorN _map;
};

template<class Useless>
class B : public Bar {
private:
class Foo;
Foo* _t;
public:
inline void update() {
_t->update();
}
};

template<class Useless>
class B<Useless>::Foo : FooBase<B<Useless>> {
private:
typedef FooBase<B<Useless>> base;
using base::_ref;
public:
Foo(const B<Useless>& f) : base(f) { };
inline void update() {
unsigned int size = 0;
for(unsigned short j = 0; j < _ref.Bar::_map.size(); ++j) {
size += _ref.Bar::_map.operator[](j).second.size(); // OK
size += static_cast<const vectorN>(_ref.Bar::_map).second.size(); // OK
size += _ref.Bar::_map.second.size(); // NOK
}
}
};

int main() {
B<void>* f = new B<void>();
f->update();
delete f;
return 0;
}[/cpp]

Can you reproduce the error on your side ? Works fine with g++ and clang++ and C++11.

0 Kudos
asd__asdqwe
Beginner
351 Views

It looks like my original title is quite misleading, but I can't edit that ... Indeed, the problem seems to be related with forward declaration, since the following code compiles fine with icpc too:

[cpp]

#include <vector>

typedef std::pair<unsigned short, std::vector<int>> pairN;
typedef std::vector<pairN> vectorN;

template<class T>
class FooBase {
protected:
const T& _ref;
public:
FooBase(const T& ref) : _ref(ref) { };
};

class Bar {
protected:
vectorN _map;
};

class B : Bar {
private:
class Foo : FooBase<B> {
private:
typedef FooBase<B> base;
using base::_ref;
public:
Foo(const B& f) : base(f) { };
inline void update() {
unsigned int size = 0;
for(unsigned short j = 0; j < _ref.Bar::_map.size(); ++j) {
size += _ref.Bar::_map.operator[](j).second.size(); // OK
size += static_cast<const vectorN>(_ref.Bar::_map).second.size(); // OK
size += _ref.Bar::_map.second.size(); // OK now
}
}
};
Foo* _t;
public:
inline void update() {
_t->update();
}
};

int main() {
B* f = new B();
f->update();
delete f;
return 0;
}[/cpp]

So how to fix my original problem now ? Thanks for your help.

0 Kudos
Judith_W_Intel
Employee
351 Views

 

I have been able to reproduce this and have entered it into our internal bug tracking database as DPD200249732. It seems to be a problem with template aliases and references. I see that you have already come up with a couple of workarounds, one other one (which actually makes the code simpler is to remove the unnecessary Bar qualification, i.e.:

#ifdef OK
      size += _ref._map.second.size();  // simpler and works as expected
#else
      size += _ref.Bar::_map.second.size(); // NOK
#endif

Thank you for bringing it to our attention.

Judy

0 Kudos
asd__asdqwe
Beginner
351 Views

Hello Judy, you are 100% right ! Thanks for the (much better) workaround. Sorry for all the trouble.

0 Kudos
Reply