views:

255

answers:

2

Hi,

I'm using Visual Studio 2008 with the Boost v1.42.0 library. If I use an enum as the template argument, I get a compile error when adding a value using push_back(). The compiler error is: 'T': is not a legal base class and the location of the error is move.hpp line 79.

#include <boost/interprocess/containers/vector.hpp>

class Test {
public:
 enum Types {
  Unknown = 0,
  First = 1,
  Second = 2,
  Third = 3
 };
 typedef boost::container::vector<Types> TypesVector;
};

int main() {
 Test::TypesVector o;

 o.push_back(Test::First);

 return 0;
}

If I use a std::vector instead it works. And if I resize the Boost version first and then set the values using the [] operator it also works.

Is there some way to make this work using push_back()?


Template backtrace of the error:

error C2516: 'T' : is not a legal base class
1>        main.cpp(21) : see declaration of 'T'
1>        main.cpp(21) : see reference to class template instantiation 'boost::interprocess::rv' being compiled
1>        with
1>        [
1>            T=Test::Types
1>        ]
A: 

It sounds like Boost has some erroneous logic to determine whether to derive from T or not.

Naively, one might assume that any type besides a native type or pointer may be used as a base. However enums are neither bases nor primitive. Perhaps they failed to account for that.

It looks like Boost is incorrectly determining that enums are compatible with its rvalue-reference emulation.

The best way to solve this is to avoid use of enums in Boost Interprocess structures.

A hack like

namespace boost {
namespace interprocess { // get inside boost
template<>
class is_movable<Test::Types> // add custom specialization of is_movable
   : public ::boost::mpl::bool_<false>
{};
}}

might patch things up. Untested.

Add this right after your #includes so it appears before the first use.

Potatoswatter
Boost v1.42.0 is the latest version.
Billy ONeal
I'm fairly novice with Boost and the host of template stuff, so I'm not sure I understand what that code does. But it appears to only add more errors in addition to the other one. `'boost::interprocess::is_movable<T>' : class template has already been defined` `'boost::interprocess::is_movable<T>' : partial specialization cannot match argument list for primary template`
CuppM
@CuppM: Sorry, upon review of the partial specialization rules, §14.5.4/9 bullet 3 says "— The argument list of the specialization shall not be identical to the implicit argument list of the primarytemplate." So my code was broken. I suggest changing to a `vector<int>` or `vector<char>` because Boost doesn't support this. For the sake of argument, hmm, I'll post a patch for just your one type.
Potatoswatter
Now I get: `'boost::interprocess::is_movable<Test::Types>' : symbol cannot be defined within namespace 'move_detail'`
CuppM
@CuppM: I misread the header. Remove the `move_detail` namespace enclosure.
Potatoswatter
Nope. That block compiles without error, but it still results in a `'T': is not a legal base class` error.
CuppM
@CuppM it comes back to knowing where the error is coming from, and you still haven't posted a backtrace. For example, this fix only works for one enum type. You'll get the same error if you're using two. Why don't you want to copy-paste your error messages?
Potatoswatter
I did copy and paste the error message from the output window in Visual Studio. That's what I added to the end of my question above. If I should be looking somewhere else, let me know and I'll post it.
CuppM
+1  A: 

I think you have find really a bug. I have posted to the Boost ML to track the issue and try to have more info.

For the moment the single workaround I see is to specialize the rv class as follows, but I'm not sure this will work on all the cases.

namespace boost {
namespace interprocess {

template <>
class rv<Test::Types> 
{
   Test::Types v;
   rv();
   ~rv();
   rv(rv const&);
   void operator=(rv const&);
   operator Test::Types() const {return v;}
};

}}

If this do not works you can try using int instead of enum.

 enum {
  Unknown = 0,
  First = 1,
  Second = 2,
  Third = 3
 };
 typedef int Types; 

Of course this has the drawback to loss the enum safety.

Vicente Botet Escriba
That appears to be a successful work around. It compiles and lets me go on my way. Could you post any links to the bug items you submit to Boost? Thank you.
CuppM
I have not yet posted a ticket, but I have started a thread on this issue (<http://old.nabble.com/-interprocess--move--enum-template-argument-fails-to-be-a-valid-base-class-tt28322112.html> and <http://old.nabble.com/Fwd%3A-Re%3A--interprocess--move--enum-template-argument-fails-to-be-a-valid-base-class-tt28325178.html>. Ion, the author of Boost.Interprocess is not confident with my workaround and is looking for a generic solution.
Vicente Botet Escriba