C++ — как правильно объявить конструктор?

Под впечатлением от вчерашней статьи про Ref-qualified (вопрос не про них, просто объясняю к чему весь огород) решил попробовать сделать такую вещь:

Заполнение переменных из вектора со следующим синтаксисом
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",...
Чтобы при этом был возможен только такой синтаксис.
Т.е. чтобы нельзя было писать так
list q(a,b,c,d,e);
q = arr;   // так нельзя
или так
list q(a,b,c,d,e),w(a,b,c,d,e);
w = q;   // так нельзя
В общем-то, все получилось. Работает для любого количества аргументов.
Но (собственно, сам вопрос), если аргумент 1. Т.е. я пишу так:
vector<string> arr{"str1","str2","str3","str4","str5","str6"};
string a;
list(a) = arr;
то компилятор думает что я повторно объявляю переменную a типа string как переменную типа 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;
              ^
а я всего лишь хочу создать объект, вызвав конструктор с одним аргументом -- той самой переменной a типа string.

Как ему объяснить, что это не повторное объявление, а вызов конструктора?

Вот код:
#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, поэтому компилировал так:
g++ -O2 -std=c++11 list.cpp -o list
Есть идеи?
  • Вопрос задан
  • 3276 просмотров
Решения вопроса 1
@xandox
Заверни struct list в приватный нэймспэс и разреши конструктор копирования
в глобальном нэймспэсе сделай так
template <class ...Args>
_p::list list(Args&& ...args) {
    return _p::list(args...);
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@encyclopedist
Ещё способ показать что это именно вызов конструктора - использовать синтаксис с фигурными скобками:
list{a} = arr;
Ответ написан
AxisPod
@AxisPod
Функция решит все ваши проблемы.

Сделайте функцию list, которая будет возвращать временный объект с перегруженным оператором =, реализуйте семантику переноса, возвращайте через std::move.

Ну и пребудет с вами сила.

А создавая явно объект вы наживаете себе больших проблем.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы