2013-03-28 14 views
6

Câu hỏi này xác định rằng một loại Non-copyable không thể sử dụng Với Boost Variantboost :: variant; std :: unique_ptr và sao chép

Tree lớp

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 lớp

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; 

Áp dụng Visitors như sau

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

Cũng sử dụng tăng :: ràng buộc đối với các thông số mong muốn

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

lỗi biên dịch của các loại

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 biên dịch một cách chính xác và đã được thử nghiệm . Làm thế nào tôi có thể giải quyết các lỗi biên dịch xuất hiện liên quan đến việc cố gắng lấy một bản sao của lớp học Tree mà, vì std::unique_ptr, chỉ là không thể?

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


}; 

Ví dụ sử dụng:

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

Mã bưu điện biên dịch, vui lòng. (và vẫn thể hiện được vấn đề) Xóa những thứ không quan trọng, nhưng vẫn chứng minh được vấn đề. Xem tại đây: http://sscce.org/ để biết các bước cần thực hiện để làm cho câu hỏi của bạn dễ dàng hơn để trả lời. – Yakk

+0

@Yakk Bài đăng gốc của tôi thể hiện vấn đề rõ ràng như tôi có thể cho một chương trình gồm mười lớp và hàng nghìn dòng mã. Nó là tốt như nó được mà không có bạn di chuyển quảng cáo vô hạn. – Mushy

+0

Không, không phải vậy. 'TreeVisitor' của bạn đang nói về' BinarySearchTree', là một loại không xuất hiện ở đâu cả. 'Tree' có phải là' BinarySearchTree' không? Hầu như tất cả các chức năng 'delete_' của bạn không liên quan đến vấn đề, làm thế nào là ngắn như bạn có thể nhận được nó? Các thành viên của 'TreeNode' có liên quan gì đến vấn đề này không? Tôi nghi ngờ điều đó. Toàn bộ điểm của một ví dụ biên dịch ngắn, khép kín là bạn thực sự viết mã * biên dịch * và trình bày vấn đề, và có mọi thứ bạn có thể loại bỏ khỏi nó trong khi vẫn trình bày vấn đề. Bạn có thể làm tốt hơn. – Yakk

Trả lời

5

Liên quan đến cuộc gọi đến boost::bind(), bạn nên sử dụng boost::ref() khi đi qua một đối tượng bằng cách tham chiếu đến một mẫu chức năng chấp nhận đối số tương ứng theo giá trị, nếu không, sẽ sao chép (dẫn đến lỗi trình biên dịch trong trường hợp này, vì không thể truy cập được hàm tạo bản sao):

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

Tuy nhiên, có vấn đề lớn hơn ở đây: boost::variant chỉ có thể chứa các loại có thể sao chép được. Từ Boost.Variant online documentation:

Các yêu cầu về một loại bị chặn như sau:

  • CopyConstructible [20.1.3].

  • Destructor duy trì bảo đảm an toàn ngoại lệ không ném.

  • Hoàn thành tại thời điểm diễn giải mẫu biến thể. (Xem boost::recursive_wrapper<T> cho một loại wrapper chấp nhận loại không đầy đủ để cho phép các loại biến thể đệ quy.)

Mỗi loại quy định như một mẫu đối số để variant phải ở mức tối thiểu đáp ứng các yêu cầu trên. [...]

+0

Tôi sử dụng 'std :: ref' quấn quanh' tree' và trình biên dịch đã đưa ra một 'lỗi C2558: class 'boost :: _ bi :: list3 ': không có hàm tạo bản sao nào có sẵn hoặc constructor sao chép được khai báo 'clear''' với A1 = boost :: _ bi :: giá trị A2 = boost :: _ bi :: giá trị , A3 = boost :: _ bi :: giá trị Mushy

+0

@Mushy: Làm thế nào về 'boost :: ref' sau đó ? Nếu điều đó không hiệu quả, tôi sẽ xóa câu trả lời này –

+0

Xuất hiện để hoạt động; trình biên dịch báo lỗi 'C2248: 'Cây :: Cây': không thể truy cập thành viên riêng được khai báo trong lớp 'Tree '' và có vấn đề với 'tree = stringTree' mà tôi nghĩ có thể yêu cầu' 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 chỉ di chuyển và có thể được sử dụng trong biến thể. Ví dụ trên có thể biên dịch và làm việc (C++ 11).