Автопреобразование из std::string и обратно.
От: dosik Россия www.dosik.ru
Дата: 22.07.16 10:27
Оценка:
Сразу оговорюсь, задача не сделать variant, а читать и записывать в строку с наибольшей гибкостью и удобством необходимые пары ключ/значение.
Значения могут быть любые: строки, отдельные символы, целые , дробные, даты и т.п.
По быстрому накидал конвертор, что-то типа:
class converter {
    std::string& pvalue;
public:
    converter(std::string& val) : pvalue(val) {};

    template <typename T>
    converter& operator=(const T& val) {
        pvalue = std::to_string(val);
        return *this;
    }

    //Можно как специализации, можно просто перегрузить. Есть принципиальная разница?
    converter& operator=(const char* val) {
        pvalue = val;
        return *this;
    }

    converter& operator=(const std::string& val) {
        pvalue = val;
        return *this;
    }

    //Тут можно добавить еще необходимые преобразования

    //Ну и обратно
    operator int () { return std::stoi(pvalue); }
    operator long () { return std::stol(pvalue); }
    operator long long () { return std::stoll(pvalue); }
    operator float () { return std::stof(pvalue); }
    operator double () { return std::stod(pvalue); }
    operator long double () { return std::stold(pvalue); }
    operator unsigned long () { return std::stoul(pvalue); }
    operator unsigned long long () { return std::stoull(pvalue); }
    operator std::string () { return pvalue; }
};

Ну и для него что-то типа:
class my_map {
    std::unordered_map<std::string, std::string> values;
public:
    converter& operator [](const std::string& key) {
        converter value(values[key]);
        return value;
    }
}

Так вот на сие чудо Clang ругается: warning: reference to stack memory associated with local variable 'value' returned [-Wreturn-stack-address] (return value
Но все работает.
GCC ругается: warning: reference to local variable ‘value’ returned [-Wreturn-local-addr] (converter value(values[key])
Но на первом же обращении по индексу случается: Signal: SIGSEGV (Segmentation fault)

В принципе все верно, компилятор не гарантирует продолжительность жизни переменной после выхода из области видимости, скорее удивительно, что я додумался такую чушь написать, а Clang ее еще и съел. Но с другой стороны converter& operator [] должен вернуть временную lvalue, которая должна жить до окончания операции копирования. Или я что-то все-таки недопонимаю?

Как вариант можно рассмотреть converter как unique_ptr член класса my_map, и при каждом обращении создавать новый. Тогда он преждевременно не умрет.
Можно рассмотреть в converter вместо ссылки std::string& pvalue; указатель std::string* pvalue;, а converter как простой член класса my_map, и при каждом вызове писать в pvalue указатель на нужный индекс. Но почему-то указатели не очень жалуют в STL.

Есть еще идеи?
И все же интересно, кто из компиляторов прав?
Re: Автопреобразование из std::string и обратно.
От: Chorkov Россия  
Дата: 22.07.16 11:16
Оценка:
Здравствуйте, dosik, Вы писали:


D>Как вариант можно рассмотреть converter как unique_ptr член класса my_map, и при каждом обращении создавать новый. Тогда он преждевременно не умрет.

А если пользователь запросит сразу два значения?
 foo( my_map["A"], my_map["B"] )


D>Можно рассмотреть в converter вместо ссылки std::string& pvalue; указатель std::string* pvalue;, а converter как простой член класса my_map, и при каждом вызове писать в pvalue указатель на нужный индекс. Но почему-то указатели не очень жалуют в STL.


D>Есть еще идеи?


1) хранить в converter экземпляр строки (и переименовать в convertable_string)
std::unordered_map<std::string, convertable_string> values;
можно возвращать ссылку на convertable_string.

2) хранить в converter ссылку/указатель на std::string,
добавить конструкторы копирования/перемещения,
возвращать converter по значению.
Re: Автопреобразование из std::string и обратно.
От: _hum_ Беларусь  
Дата: 22.07.16 11:18
Оценка:
не сосем понятно, что именно вы хотите, но

1) компиляторы и тот, и другой правильно ругаются — никто не гарантирует вам живучесь ссылок на локальные объекты по выходу из области видимости
2) зачем вы тут
  code
class my_map {
    std::unordered_map<std::string, std::string> values;
public:
    converter& operator [](const std::string& key) {
        converter value(values[key]);
        return value;
    }
}

пытаетесь вернуть l-value, ведь модифицировать это значение явно же не имеет смысла? в общем, я бы сначала над семантикой подумал — "что-то тут не то".
Re: Автопреобразование из std::string и обратно.
От: uzhas Ниоткуда  
Дата: 22.07.16 12:11
Оценка:
Здравствуйте, dosik, Вы писали:

D> скорее удивительно, что я додумался такую чушь написать

так точно

D>Есть еще идеи?

вам нужно вернуть convertor по значению
Re[2]: Автопреобразование из std::string и обратно.
От: dosik Россия www.dosik.ru
Дата: 22.07.16 12:12
Оценка:
Здравствуйте, _hum_, Вы писали:

__>2) зачем вы ... пытаетесь вернуть l-value, ведь модифицировать это значение явно же не имеет смысла?


Бинго!!! Индекс перегружаю впервые (раньше не было такой необходимости), клинануло, что перегружая индекс можно возвращать только ссылки
Если возвращать значения, то все стало гораздо проще:
class converter {
    std::string& pvalue;
public:
    converter (std::string& str) : pvalue(str) {};

    template <typename T>
    converter& operator=(const T& val) {
        pvalue = std::to_string(val);
        return *this;
    }
...
}

class my_map {
    std::unordered_map<std::string, std::string> values;
public:

    converter operator [](const std::string& key) {
        return converter(values[key]);
    }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.