バリアントの配列を文字列から生成して遊んでみました。テンプレートを使うと型情報による switch & case がなくて気持ちいいですね。C++17 以降の環境なら Variant には std::variant<> を使うべきでしょうけれども。
#include <string> #include <sstream> #include <vector> #include <memory> #include <stdexcept> // boost::lexical_cast<> みたいなもの struct Lexer { template <class Type> static Type to(const std::string& string) { std::stringstream stream(string); Type value; stream >> value; if (stream.fail() || stream.peek() != std::stringstream::traits_type::eof()) { throw std::runtime_error("Type missmatch error"); } return value; } }; template <> bool Lexer::to<bool>(const std::string& string) { std::stringstream stream(string); bool value; stream >> std::boolalpha >> value; if (stream.fail()) { switch (to<int>(string)) { case 0: value = false; break; case 1: value = true; break; default: throw std::runtime_error("Type missmatch error"); } } return value; } // TODO : int, float を特殊化して stol, stof で最適化する。 // 任意の型のデータ struct Variant { template <class Type> void set(Type value) = delete; template <class Type> decltype(auto) get() const = delete; // いずれ参照も返す private: enum class Type { boolean, integer, real } type = Type::boolean; union { bool boolean = false; int integer; float real; }; void validate(Type target) const { if (type != target) { throw std::runtime_error("Type missmatch error"); } } }; template <> void Variant::set<bool>(bool value) { type = Type::boolean, boolean = value; } template <> void Variant::set<int>(int value) { type = Type::integer, integer = value; } template <> void Variant::set<float>(float value) { type = Type::real, real = value; } template <> decltype(auto) Variant::get<bool>() const { validate(Type::boolean); return boolean; } template <> decltype(auto) Variant::get<int>() const { validate(Type::integer); return integer; } template <> decltype(auto) Variant::get<float>() const { validate(Type::real); return real; } // 任意の型のデータ配列 class VariableArray { private: explicit VariableArray(std::vector<Variant>&& converted): array(std::move(converted)) { } public: auto& get(std::size_t index) const { return array[index]; } auto size() const { return array.size(); } public: template <class Type> static std::shared_ptr<VariableArray> create(const std::vector<std::string>& source) { std::vector<Variant> converted; for (auto& item : source) { converted.emplace_back(); converted.back().set(Lexer::to<Type>(item)); } struct VariableArrayHelper : public VariableArray { VariableArrayHelper(std::vector<Variant>&& converted): VariableArray(std::move(converted)) {} }; auto instance = std::make_shared<VariableArrayHelper>(std::move(converted)); return std::move(instance); } private: std::vector<Variant> array; }; // テスト #include <cassert> int main(int argc, char* argv[]) { // boolean auto barray = VariableArray::create<bool>({ "true", "false", "1", "0" }); assert(barray->size() == 4); assert(barray->get(0).get<bool>() == true); assert(barray->get(1).get<bool>() == false); assert(barray->get(2).get<bool>() == true); assert(barray->get(3).get<bool>() == false); auto exception_occured = false; try { barray->get(0).get<int>(); } catch (std::exception& ex) { exception_occured = true; } assert(exception_occured); // integer auto iarray = VariableArray::create<int>({ "50", "34" }); assert(iarray->size() == 2); assert(iarray->get(0).get<int>() == 50); assert(iarray->get(1).get<int>() == 34); exception_occured = false; try { iarray->get(0).get<bool>(); } catch (std::exception& ex) { exception_occured = true; } assert(exception_occured); // real auto farray = VariableArray::create<float>({ "50", "34.2" }); assert(farray->size() == 2); assert(farray->get(0).get<float>() == 50.f); assert(farray->get(1).get<float>() == 34.2f); exception_occured = false; try { farray->get(0).get<bool>(); } catch (std::exception& ex) { exception_occured = true; } assert(exception_occured); return 0; }