понедельник, 20 июня 2016 г.

Class templates and error message with C++11:[your copy constructor] is implicitly deleted because the default definition would be ill-formed


The nice thing about C++11 and C++14 standards is that they help you to code a bit less and to achieve a better results. But there are some pitfall from time to time and you have to be attentive to the compiler's error messages. For example as soon as you add to your class/class template a mutex or other C++11 primitive with implicitly deleted copy and move constructors and try to return the value of your type then you may get the error:

[YOUR COPY CONSTRUCTOR DEFINITION] use of deleted function
[YOUR COPY CONSTRUCTOR DEFINITION] is implicitly deleted because the default definition would be ill-formed.

You say Ok, I know that mutex has deleted copy and move constructors. You read articles like these:
And you say: YES, I can explicitly add copy constructor and = operator to my template. Lets put it in this way - you have Collection template and Node class:

template class Collection
{
private:
    list  m_Items;
    mutex m_Lock;
public:
    Collection()=default;

    Collection(const T& source) {/* you code goes here*/}
    Collection& operator = (T& other){/* you code goes here*/}

//...
}
And lets your Node class look like this:

class Node
{
protected:
    string     m_strName;
    string     m_strText;
    Collection   m_ChildNodes;
    Collection   m_Attributes;
    mutex m_vLock;
public:
    Node() =default;

    Node(const XmlNode& node) {/* you code goes here*/}
    Node& operator=(XmlNode const&) {/* you code goes here*/}

/...
}

The template Collection is used to work with your Node. Suppose you do this way:

Collection < Node > Node::getElements(const char* strTagName)
{
    Collection < Node > list;

    lock_guard lock(m_Lock);
/*
some code goes here...
*/

    return list;//error!!!
    //use of deleted function ‘Collection::Collection(Collection & )
    //note: ‘Collection::Collection(const Collection &)’ is implicitly deleted because the default definition would be ill-formed:
}

And you still get this anoying error...
Ok. The solution is very simple: you have to define the correct copy constructor and = operator. Collection actually requires these constructors with template parameters:
    Collection(Collection < T > & source){/* you code goes here*/}

    Collection < T > operator = (Collection < T > & other){/* you code goes here*/}

AND:
    Node(const XmlNode & node){/* you code goes here*/}
    Node& operator=(XmlNode const &){/* you code goes here*/}

The bottom line is: be attentive to compiler's error messages! In case of templates you have to provide correct constructors.