8

This Question Determined That a Non-Copyable Type Can't Be Used With Boost Variant

Tree class

template <class T = int>

class Tree{

private:

         class TreeNode{

         public:
                 std::unique_ptr Nodes
                 Move constructors and move assignment + other public members

         private:

                 TreeNode(const TreeNode &other);      (= delete not supported on compiler)
                 TreeNode& operator=(const TreeNode &rhs);    (= delete not supported on compiler)


         };  // End Tree Node Class Definition


         Tree(const Tree &other);     (= delete not supported on compiler)
         Tree& operator=(const Tree &rhs);    (= delete not supported on compiler)

public:

         Move constructors and move assignment + other public members
};

TreeVisitor class

class TreeVisitor : public boost::static_visitor<bool> {
public:
        TreeVisitor() {}

        bool operator() (BinarySearchTree<std::string>& tree) const {
            return searchTree.load(tree);
        }
private:

};

TreeVariant

typedef boost::variant<Tree<std::string>, Tree<int>> TreeVariant;     
TreeVariant tree;

Tree<std::string> stringTree;
Tree<int> intTree;

Applying Visitors as follows

tree = intSearchTree;
boost::apply_visitor(TreeVisitor(), tree)

Also using boost::bind for desired parameters

boost::bind(TreeVisitor(), tree, val, keyIndex);

Compiler errors of the type

error C2248: 'Tree<T>::Tree' : cannot access private member declared in class 'Tree<T>'  <----- related to private copy constructor in Tree (not TreeNode)
tree = stringTree;  <-------  error related to assignment

Tree compiles correctly and has been tested. How can I resolve these compilation errors that appear related to trying to obtain a copy of the Tree class which, because of std::unique_ptr, is just not possible?

SSCCE

<class T = int>

class Tree{

private:

class TreeNode{

public:

    TreeNode() {}
    ~TreeNode() {}  

    TreeNode(TreeNode &&other) : 
        key(other.key), index(other.index), left(std::move(other.left)), right(std::move(other.right)) 
    {
        key = index = left = right = nullptr; 
    }

    TreeNode &operator=(BTreeNode &&rhs)
    { 
        if(this != &rhs) 
        { 
            key = rhs.key; index = rhs.index; 
            left = std::move(rhs.left); right = std::move(rhs.right); 
            rhs.key = rhs.index = rhs.left = rhs.right = nullptr;
        } 
        return *this;
    }

    TreeNode(const T &new_key, const T &new_index) :
        key(new_key), index(new_index), left(nullptr), right(nullptr) {}

    friend class Tree;

private:

    TreeNode(const BinarySearchTreeNode &other);
    TreeNode& operator=(const BinarySearchTreeNode &rhs);

    std::unique_ptr<TreeNode> left;
    std::unique_ptr<TreeNode> right;

};  // End Tree Node Class Definition

std::unique_ptr<TreeNode> root;

BinarySearchTree(const BinarySearchTree &other);
BinarySearchTree& operator=(const BinarySearchTree &rhs);


public:

Tree() : root(nullptr), flag(false), run(true), leftCount(0), rightCount(0) {}

~Tree() {}

Tree(BinarySearchTree &&other) : root(std::move(other.root)) { other.root = nullptr; }

Tree &operator=(BinarySearchTree &&rhs) 
{ 
    if(this != &rhs)
    { 
        root = std::move(rhs.root); 
        rhs.root = nullptr;
    } 
    return *this;
}


};

Example use:

bool delete_(){

    while(!instances.empty()){
                    // grab first instance
                    keyIndex = instances.at(0);
                    // compute end of the tuple to delete
                    endIndex = keyIndex + sizeToDelete;

                    // read the first attribute
                    try{
                        temp = boost::trim_copy(dataFile->readData(keyIndex, domainSize));
                    }
                    catch (std::exception &e){
                        printw("Error reading from the data file");
                    }

                    // delete tuple from data file
                    if(!dataFile->deleteTuple(keyIndex, endIndex)){
                        printw("Error attempting to remove tuple");
                        if (writer_ != nullptr)
                            writer_ << "Error attempting to remove tuple";
                        try{
                            printw("%s");
                            // close catalog and search file

                        }
                        catch (std::exception &e){
                            e.what();
                        }
                        // close data file
                        dataFile->closeFile();
                        return false;
                    }


                    try{
                        int val = boost::lexical_cast<int>(temp);

                        searchTree = intSearchTree;

                        boost::bind(BinarySearchTreeVisitor(), searchTree, val, keyIndex);

                        // delete key index from the index file
                        if (!boost::apply_visitor(BinarySearchTreeVisitor(), searchTree)){
                            printw("No index present in index file");
                            try{
                                printw(" ");

                            }
                            catch (std::exception &e){

                            }
                            // close data file
                            dataFile->closeFile();
                            return false;           
                        }
                    }
                    catch(boost::bad_lexical_cast &e){

                        /*
                         * Must be a std::string --- wow who knew
                         */

                        searchTree = stringSearchTree;

                        boost::bind(BinarySearchTreeVisitor(), searchTree, temp, keyIndex);

                        // delete key index from the index file
                        if (!boost::apply_visitor(BinarySearchTreeVisitor(), searchTree)){
                            printw("No index present in index file");
                            try{
                                printw(" ");
                                // close catalog and search file

                            }
                            catch (std::exception &e){
                                e.what();
                            }
                            // close data file
                            dataFile->closeFile();
                            return false;           
                        }

                    }                       

                    // clean up the index file
                    boost::bind(BinarySearchTreeVisitor(), searchTree, keyIndex, sizeToDelete);
                    boost::apply_visitor(BinarySearchTreeVisitor(), searchTree);

                    instances.erase(instances.begin());

                    for(int i= 0; i < instances.size(); i++){
                        instances.assign(i, instances.at(i) - 
                                                            sizeToDelete);
                    }

                }
}
Mushy
  • 2,535
  • 10
  • 33
  • 54
  • 2
    Post code that compiles, please. (and still demonstrates the problem) Delete things that aren't important, but still demonstrate the problem. Look here: http://sscce.org/ for steps to take to make your question easier to answer. – Yakk - Adam Nevraumont Mar 28 '13 at 18:51
  • @Yakk My original post demonstrates the problem as clear as I can for a program of ten classes and thousands of lines of code. It is as good as it gets without having you scroll ad infinitum. – Mushy Mar 28 '13 at 19:11
  • No, it isn't. Your `TreeVisitor` is talking about `BinarySearchTree`, which is a type that comes out of nowhere. Is `Tree` supposed to be `BinarySearchTree`? Almost all of your `delete_` function is irrelevant to the problem, how is that as short as you can get it? Do the members of `TreeNode` have anything to do with the problem? I doubt it. The entire point of a short, self contained, compiling example is that you actually write code that *compile*s and demonstrates the problem, and has everything you can eliminate removed from it while still demonstrating the problem. You can do better. – Yakk - Adam Nevraumont Mar 28 '13 at 19:48
  • And saying "move constructors go here" is not helpful. If they are not important, just omit them. If they are important, include them, and remove as much as you can from them until they only contain the important part. Then repeat. – Yakk - Adam Nevraumont Mar 28 '13 at 19:49
  • @Yakk Corrected `BinarySearchTree` to be a `Tree` and posted an SSCCE. I sought to provide, not an SSCCE, but an understandable breakdown of a very large program I am writing. I am sorry you have taken exception, and offer you my apologies in earnest! – Mushy Mar 28 '13 at 20:03

2 Answers2

6

Concerning the call to boost::bind(), you should use boost::ref() when passing an object by reference to a function template that accepts the corresponding argument by value, otherwise a copy will be attempted (which results in a compiler error in this case, since the copy constructor is inaccessible):

boost::bind(TreeVisitor(), boost::ref(tree), val, keyIndex);
//                         ^^^^^^^^^^^^^^^^

However, there is a bigger problem here: boost::variant can only hold types which are copy-constructible. From the Boost.Variant online documentation:

The requirements on a bounded type are as follows:

  • CopyConstructible [20.1.3].

  • Destructor upholds the no-throw exception-safety guarantee.

  • Complete at the point of variant template instantiation. (See boost::recursive_wrapper<T> for a type wrapper that accepts incomplete types to enable recursive variant types.)

Every type specified as a template argument to variant must at minimum fulfill the above requirements. [...]

Community
  • 1
  • 1
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • I utilized `std::ref` wrapped around `tree` and the compiler issued an `error C2558: class 'boost::_bi::list3' : no copy constructor available or copy constructor is declared 'explicit'` `with A1=boost::_bi::value A2=boost::_bi::value, A3=boost::_bi::value – Mushy Mar 28 '13 at 19:20
  • @Mushy: How about `boost::ref` then? If that doesn't work, I will delete this answer – Andy Prowl Mar 28 '13 at 19:21
  • Appears to work; compiler states `error C2248: 'Tree::Tree' : cannot access private member declared in class 'Tree'` and has a problem with `tree = stringTree` which I think may require a `std::move`. – Mushy Mar 28 '13 at 19:27
  • @Mushy: Yes, that's definitely the case. `tree = stringTree` would attempt a copy-construction – Andy Prowl Mar 28 '13 at 19:28
  • Ok, then I am going to apply a std::move patch – Mushy Mar 28 '13 at 19:29
  • Compiler is happy about most except this declaration `typedef boost::variant, Tree> TreeVariant; TreeVariant searchTree; <------------- That guy` as well as still barking about private copy constructors in `Tree`. – Mushy Mar 28 '13 at 19:39
  • @Mushy: See my last edit to the answer: actually, you cannot hold a type which is not copy constructible in a `boost::variant`. – Andy Prowl Mar 28 '13 at 19:47
  • Then game over and I greatly appreciate the discourse. I will have to switch to std::shared_ptr then and thank everyone for commenting. Though not the solution I desired, your input is the answer. – Mushy Mar 28 '13 at 20:04
  • 3
    I think the `CopyConstructible` requirement is a documentation bug – from the [Boost 1.53.0 change notes](http://www.boost.org/users/history/version_1_53_0.html): "*Variant: Added rvalue constructors and rvalue assignment operators (for C++11 compatible compilers only). Library now can be used with move-only types.*" – ildjarn Apr 04 '13 at 17:10
1
using Mixed = boost::variant< 
  std::unique_ptr<char>,
  std::unique_ptr<short>,
  std::unique_ptr<int>,
  std::unique_ptr<unsigned long>
>;

int main() {    
  auto md = std::unique_ptr<int>(new int(123));
  Mixed mixed = std::move(md);
  std::cout << *boost::get< std::unique_ptr<int> >(mixed) << std::endl;
  return 0;
}

unique_ptr is move-only and can be used in variant. The above example can compile and work (C++11).

DuffyChan
  • 119
  • 1
  • 9