Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost variant busted in 1_54?

I think Boost::variant is busted in 1_54. I am trying to use a std::unique_ptr with as a bounded type in boost variant.

According to the 1_54 documentation, variant needs to be copy constructable or Move Constructable.

http://www.boost.org/doc/libs/1_54_0/doc/html/variant/reference.html

So I implemented the move constructors and disabled the copy constructors in my code.

When I try to assign something to the variant object it fails to compile. I have tried various different things including using std::move to assign data to the variant object, but nothing seems to work. Following the compilation error stack trace I determined the problem is in variant.hpp, where its trying to backup the rhs data. I would like to know what you guys think and let me know if I right to assume boost variant documentation is wrong.

Thanks in advance.

I am compiling with vs2010 and using C++11.

Here is my Test Code:

#include <iostream>
#include <memory>
#include <utility>
#include <vector>
#include <string>


#pragma warning (push)
#pragma warning (disable: 4127 4244 4265 4503 4512 4640 6011)
#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include <boost/ref.hpp>
#include <boost/shared_ptr.hpp>
#pragma warning (pop)

#include <boost/foreach.hpp>
#include <boost/format.hpp>
using boost::format;
using boost::str;

using namespace std;

class UniqueTest
{
};

class Foo
{
  public:
  std::unique_ptr<UniqueTest> testUniquePtr;

     Foo()      { std::cout << "Foo::Foo\n";  }
     Foo (Foo&& moveData)
     {
     }               

     Foo& operator=(Foo&& moveData)
     {
     return *this;
     }

  private:
     Foo(Foo& tt);
     Foo& operator=(const Foo& tt);

};


int main()
{

  Foo x = Foo();
  boost::variant<std::wstring,Foo> m_result2;
     std::wstring  testString = L"asdf";

  m_result2 = testString; //Fails
  //m_result2 = std::move(testString); //Fails
  //m_result2 = std::move(x); //Fails

  boost::get<Foo>(m_result2).testUniquePtr.get ();
  return 0;
}
like image 797
luke signh Avatar asked Nov 01 '13 00:11

luke signh


1 Answers

Does my code as is compile for anyone?

No it doesn't, variant will try to invoke the copy constructor, which is missing. (Foo::Foo(Foo const&) isn't even declared):

boost/variant/variant.hpp|756 col 9| error: no matching function for call to ‘Foo::Foo(const Foo&)’

Even if you did declare it, it wouldn't work:

test.cpp|43 col 6| error: ‘Foo::Foo(const Foo&)’ is private

It has been mentioned in the comments but you need

  • to make the copy constructor a copy constructor (for good style)

    Foo(Foo const& tt) = delete;
    Foo& operator=(const Foo& tt) = delete;
    
  • to make the move constructor/assignment noexcept, otherwise (like std::vector) variant will refuse to move things because it wouldn't be exception safe.

    Foo(Foo && moveData) noexcept { }    
    Foo& operator=(Foo && moveData) noexcept { return *this; }
    

Here's a simplified sample that compiles on GCC and Clang:

#include <iostream>
#include <memory>
#include <string>
#include <boost/variant.hpp>

struct UniqueTest { };

struct Foo
{
public:
    std::unique_ptr<UniqueTest> testUniquePtr;

    Foo() { std::cout << "Foo::Foo\n"; }
    Foo(Foo && moveData) noexcept { }

    Foo& operator=(Foo && moveData) noexcept { return *this; }

    Foo(Foo const& tt) = delete;
    Foo& operator=(const Foo& tt) = delete;
};


int main()
{
    Foo x = Foo();

    boost::variant<std::wstring, Foo> m_result2;

    std::wstring  testString = L"asdf";
    m_result2 = testString; //Fails
    //m_result2 = std::move(testString); //Fails
    //m_result2 = std::move(x); //Fails
    boost::get<Foo>(m_result2).testUniquePtr.get();
}
like image 136
sehe Avatar answered Nov 20 '22 10:11

sehe