2013-03-28 2 views
6

Этот вопрос установлено, что Non-Copyable Тип не может быть использован с подталкивания Variantboost :: variant; станд :: unique_ptr и копия

Tree класса

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

Применение Visitors следующим

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

Кроме того, используя повышение :: привязку требуемых параметров

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

ошибки компилятора типа

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 компилирует правильно и протестировано , Как я могу устранить эти ошибки компиляции, которые появляются, связанные с попыткой получить копию класса Tree, который из-за std::unique_ptr просто невозможно?

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


}; 

Пример использования:

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

Почтовый код, который скомпилируется, пожалуйста. (и все еще демонстрирует проблему) Удалите вещи, которые не важны, но все еще демонстрируют проблему. Посмотрите здесь: http://sscce.org/ для принятия мер, чтобы ваш вопрос был легче ответить. – Yakk

+0

@Yakk Мое первоначальное сообщение демонстрирует проблему настолько ясную, насколько я могу, для программы из десяти классов и тысяч строк кода. Это так же хорошо, как и до тех пор, пока вы не прокрутите до бесконечности. – Mushy

+0

Нет, это не так. Ваш 'TreeVisitor' говорит о' BinarySearchTree', который является типом, который выходит из ниоткуда. Предполагается, что 'Tree' должен быть' BinarySearchTree'? Почти вся ваша функция 'delete_' не имеет отношения к проблеме, как это так коротко, как вы можете ее получить? У членов «TreeNode» есть какие-либо проблемы с проблемой? Я сомневаюсь в этом. Вся суть короткого, самодостаточного, компилирующего примера состоит в том, что вы на самом деле пишете код, который * компилирует * s и демонстрирует проблему, и имеет все, что вы можете устранить, удалив из него, все еще демонстрируя проблему. Ты можешь лучше. – Yakk

ответ

5

Относительно вызов boost::bind(), вы должны использовать boost::ref() при прохождении объекта по ссылке на шаблон функции, которая принимает соответствующий аргумент по значению, в противном случае будет выполнена копия (что приводит к ошибке компилятора в этом случае, поскольку конструктор копирования недоступен):

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

Однако здесь существует большая проблема: boost::variant может хранить только те типы, которые можно скопировать. От Boost.Variant online documentation:

Требования к ограниченному типа заключаются в следующем:

  • CopyConstructible [20.1.3].

  • Деструктор поддерживает гарантию безопасности без броска.

  • Выполняется при создании экземпляра варианта варианта. (См boost::recursive_wrapper<T> для типа обертки, которая принимает неполные типы, чтобы позволить рекурсивные типы вариантные.)

Каждый тип, указанный в качестве аргумента шаблона для variant должен как минимум выполнить вышеуказанные требования. [...]

+0

Я использовал 'std :: ref', обернутый вокруг' tree', и компилятор выпустил 'error C2558: class 'boost :: _ bi :: list3 ': никакой конструктор копирования или конструктор копирования не объявлен 'explicit'' ' A1 = boost :: _ bi :: value A2 = boost :: _ bi :: значение , A3 = boost :: _ bi :: значение Mushy

+0

@Mushy: Как насчет 'boost :: ref' тогда ? Если это не сработает, я удалю этот ответ –

+0

Появляется на работе; ошибка компилятора: ошибка C2248: «Дерево :: Дерево»: не может получить доступ к частному члену, объявленному в классе «Дерево », и имеет проблему с 'tree = stringTree', который, как мне кажется, может потребовать' 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 это движение только и может быть использован в варианте. Вышеприведенный пример может компилироваться и работать (C++ 11).

Смежные вопросы