Сразу оговорюсь, задача не сделать 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.
Есть еще идеи?
И все же интересно, кто из компиляторов прав?