Под впечатлением от
вчерашней статьи про 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
Есть идеи?