2013-03-28 22 views
6

To Pytanie ustalił, że dla Copyable typu nie może być używany z doładowania Variantboost :: wariant; std :: unique_ptr i skopiuj

Tree klasy

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 klasa

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; 

Stosując Visitors następująco

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

również za pomocą boost :: wiążą pożądanych parametrów

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

błędy kompilatora typu

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 kompiluje poprawnie i został przetestowany . Jak mogę rozwiązać te błędy kompilacji, które pojawiają się w związku z próbą uzyskania kopii klasy Tree, która z powodu std::unique_ptr jest po prostu niemożliwa?

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; 
} 


}; 

Przykład użycia:

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); 
        } 

       } 
} 
+2

Kod pocztowy, który kompiluje, proszę. (i nadal demonstruje problem) Usuń rzeczy, które nie są ważne, ale nadal demonstruj problem. Zajrzyj tutaj: http://sscce.org/, aby dowiedzieć się, co zrobić, aby łatwiej odpowiedzieć na twoje pytanie. – Yakk

+0

@Yakk Mój oryginalny post demonstruje problem tak czysty, jak tylko mogę, dla programu złożonego z dziesięciu klas i tysięcy linii kodu. Jest tak dobry, jak to możliwe bez przewijania reklamy w nieskończoność. – Mushy

+0

Nie, nie jest. Twój 'TreeVisitor' mówi o' BinarySearchTree', który jest rodzajem, który pojawia się znikąd. Czy 'Tree' ma być' BinarySearchTree'? Niemal cała twoja funkcja 'delete_' jest nieistotna dla problemu, jak to jest tak krótkie, jak to tylko możliwe? Czy członkowie 'TreeNode' mają cokolwiek wspólnego z problemem? Wątpię. Cały krótki krótki, samodzielny przykład kompilacji polega na tym, że faktycznie piszesz kod, który * kompiluje * i demonstruje problem, i ma wszystko, co możesz wyeliminować z niego usunięte, wciąż demonstrując problem. Możesz zrobić lepiej. – Yakk

Odpowiedz

5

chodzi o wezwanie do boost::bind(), należy użyć boost::ref() przechodząc obiektu poprzez odniesienie do szablonu funkcji, które akceptuje odpowiedniego argumentu przez wartość, w przeciwnym razie zostanie podjęta próba kopiowania (co spowoduje błąd kompilatora w tym przypadku, ponieważ konstruktor kopiowania jest niedostępny):

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

Istnieje jednak większy problem: boost::variant może zawierać tylko typy, które można skopiować. Z Boost.Variant online documentation:

Wymagania dotyczące typu ograniczonego są następujące:

  • CopyConstructible [20.1.3].

  • Destruktor podtrzymuje wyjątkową gwarancję bezpieczeństwa braku rzutu.

  • Uzupełnij w punkcie wariantu tworzenia szablonu. (Patrz boost::recursive_wrapper<T> do owinięcia typu, który akceptuje niepełne rodzaje włączyć rekurencyjnych typów wariantowych.)

każdy rodzaj określony jako argument szablonu musi wynosić minimum variant spełniać powyższe wymagania. [...]

+0

Użyłem 'std :: ref' owiniętego wokół' tree', a kompilator wydał 'error C2558: class 'boost :: _ bi :: list3 ': brak konstruktora kopiowania lub konstruktor copy został zadeklarowany jako 'explicit''' z A1 = boost :: _ bi :: value A2 = boost :: _ bi :: value , A3 = boost :: _ bi :: value Mushy

+0

@Mushy: Co powiesz na 'boost :: ref' then ? Jeśli to nie zadziała, usunę tę odpowiedź. –

+0

Pojawia się do pracy; stan kompilatora "błąd C2248:" Drzewo :: Drzewo ": nie można uzyskać dostępu do prywatnego członka zadeklarowanego w klasie" Drzewo "i ma problem z' tree = stringTree', który moim zdaniem może wymagać 'std :: move'. – Mushy

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 przemieści się tylko i może być stosowany w wariancie. Powyższy przykład może się kompilować i pracować (C++ 11).