V
V
Valery Dmitriev2014-03-25 02:42:25
C++ / C#
Valery Dmitriev, 2014-03-25 02:42:25

C++ - how to correctly declare a constructor?

Impressed by yesterday's article about Ref-qualified ( the question is not about them, I'm just explaining what the whole garden is for ) I decided to try to do this thing:
Filling variables from a vector with the following syntax

vector<string> arr{"str1","str2","str3","str4","str5","str6"};
string a,b,c,d,e;
list(a,b,c,d,e) = arr; // в результате a == "str1", b == "str2",...
That at the same time only such syntax was possible.
Those. not to write like this
list q(a,b,c,d,e);
q = arr;   // так нельзя
or so
list q(a,b,c,d,e),w(a,b,c,d,e);
w = q;   // так нельзя
In general, everything worked out. Works for any number of arguments.
But (actually, the question itself ), if the argument is 1. I.e. I write like this:
vector<string> arr{"str1","str2","str3","str4","str5","str6"};
string a;
list(a) = arr;
then the compiler thinks that I am re-declaring a variable a of type string as a variable of type list
list.cpp:100:8: error: conflicting declaration ‘list a’
  list(a) = arr;
        ^
list.cpp:98:14: error: ‘a’ has a previous declaration as ‘std::string a’
  std::string a,b,c,d,e;
              ^
and I just want to create an object by calling the constructor with one argument - the same variable a of type string.
How to explain to him that this is not a repeated declaration, but a constructor call?
Here is the code:
#include <iostream>
#include <vector>

struct list
{
    /**
     *  Constructor with one argument
     */
    explicit list(std::string& arg)
    {
        size = 1;
        parr = new std::string*[1];
        helper(0, arg);
    }

    /**
     *  Constructor with a variable (>1) number of arguments
     *    You can use any number of arguments of type std::string in the constructor.
     *    list(a,b,c,d) = arr;
     *    list(a,b) = arr;
     */
    template <typename ...Args>
    list(std::string& arg0, Args&... args)
    {
        size = sizeof...(Args)+1;
        parr = new std::string*[size];
        helper(0, arg0, args...);
    }

    /**
     *  Assignment operator
     *  Ref-qualified forbids such things:
     *  list c(a,b);
     *  c = arr;
     *  You can only use this form:
     *  list(a,b) = arr;
     */
    list &operator=(std::vector<std::string> &arr) && // <-- Ref-qualified
    {
        unsigned int min = (size < arr.size()) ? size : arr.size();
        for(unsigned int i = 0; i < min; i++)
        {
            *parr[i] = arr[i];
        }
    }

    /**
     *  Deleted constructors. Forbids such things:
     *  list q(a,b,c,d,e),w(a,b,c,d,e);
     *  w = q;
     *  You can only use this form:
     *  list(a,b,c,d,e) = arr;
     */
    list(const list &that) = delete;
    list(list &&that) = delete;
    list() = delete;
    
    ~list()
    {
        delete [] parr;
    }

private:

    /**
     *  Helper method.
     *  Allows to initialize the list of any number of arguments.
     *  Alternately, one by one makes pointers to the arguments into the internal array.
     */
    template <typename ...Args>
    void helper(int ind, std::string& arg0, Args&... args)
    {
        helper(ind, arg0);
        helper(++ind, args...);
    }
    
    /**
     *  Helper method.
     */
    void helper(int ind, std::string& arg0)
    {
        parr[ind] = &arg0;
    }
    
    // Internal array of pointers to pointers to arguments
    std::string **parr;
    // The number of arguments with which the constructor was called
    unsigned int size;
};


int main(){
        
        std::vector<std::string> arr{"str1","str2","str3","str4","str5","str6"};
        std::string a,b,c,d,e;
        //list(a,b,c,d,e) = arr;    <-- так все работает
        list(a) = arr;           // <-- а так получаю error: ‘a’ has a previous declaration as ‘std::string a’
        
        // The following code forbidden:
        // list q(a,b,c,d,e);
        // q = arr;
        // error: passing ‘list’ as ‘this’ argument of ‘list& list::operator=(std::vector<std::string>&) &&’ discards qualifiers

        // The following code forbidden:
        // list q(a,b,c,d,e),w(a,b,c,d,e);
        // w = q;
        // error: use of deleted function ‘list& list::operator=(const list&)’

        std::cout << std::endl << a << " " << b << " " << c << " " << d << " " << e << std::endl;

        return 0;
};
C++11 is used, so I compiled it like this:
g++ -O2 -std=c++11 list.cpp -o list
Any ideas?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
X
xandox, 2014-03-25
@rotor

Wrap struct list in private namespace and enable copy constructor
in global namespace do like this

template <class ...Args>
_p::list list(Args&& ...args) {
    return _p::list(args...);
}

I
Ilya Popov, 2014-03-25
@encyclopedist

Another way to show that this is a constructor call is to use the syntax with curly braces:
list{a} = arr;

A
AxisPod, 2014-03-26
@AxisPod

The function will solve all your problems.
Make a list function that will return a temporary object with an overloaded = operator, implement transfer semantics, return via std::move.
Well, the force will be with you.
And by creating an explicit object, you are making big problems for yourself.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question