diff dep/toml11/toml/value.hpp @ 318:3b355fa948c7

config: use TOML instead of INI unfortunately, INI is not enough, and causes some paths including semicolons to break with our current storage of the library folders. so, I decided to switch to TOML which does support real arrays...
author Paper <paper@paper.us.eu.org>
date Wed, 12 Jun 2024 05:25:41 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/value.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,2037 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_VALUE_HPP
+#define TOML11_VALUE_HPP
+#include <cassert>
+
+#include "comments.hpp"
+#include "exception.hpp"
+#include "into.hpp"
+#include "region.hpp"
+#include "source_location.hpp"
+#include "storage.hpp"
+#include "traits.hpp"
+#include "types.hpp"
+#include "utility.hpp"
+
+namespace toml
+{
+
+namespace detail
+{
+
+// to show error messages. not recommended for users.
+template<typename Value>
+inline region_base const* get_region(const Value& v)
+{
+    return v.region_info_.get();
+}
+
+template<typename Value>
+void change_region(Value& v, region reg)
+{
+    v.region_info_ = std::make_shared<region>(std::move(reg));
+    return;
+}
+
+template<value_t Expected, typename Value>
+[[noreturn]] inline void
+throw_bad_cast(const std::string& funcname, value_t actual, const Value& v)
+{
+    throw type_error(detail::format_underline(
+        concat_to_string(funcname, "bad_cast to ", Expected), {
+            {v.location(), concat_to_string("the actual type is ", actual)}
+        }), v.location());
+}
+
+// Throw `out_of_range` from `toml::value::at()` and `toml::find()`
+// after generating an error message.
+//
+// The implementation is a bit complicated and there are many edge-cases.
+// If you are not interested in the error message generation, just skip this.
+template<typename Value>
+[[noreturn]] void
+throw_key_not_found_error(const Value& v, const key& ky)
+{
+    // The top-level table has its region at the first character of the file.
+    // That means that, in the case when a key is not found in the top-level
+    // table, the error message points to the first character. If the file has
+    // its first table at the first line, the error message would be like this.
+    // ```console
+    // [error] key "a" not found
+    //  --> example.toml
+    //    |
+    //  1 | [table]
+    //    | ^------ in this table
+    // ```
+    // It actually points to the top-level table at the first character,
+    // not `[table]`. But it is too confusing. To avoid the confusion, the error
+    // message should explicitly say "key not found in the top-level table",
+    // or "the parsed file is empty" if there is no content at all (0 bytes in file).
+    const auto loc = v.location();
+    if(loc.line() == 1 && loc.region() == 0)
+    {
+        // First line with a zero-length region means "empty file".
+        // The region will be generated at `parse_toml_file` function
+        // if the file contains no bytes.
+        throw std::out_of_range(format_underline(concat_to_string(
+            "key \"", ky, "\" not found in the top-level table"), {
+                {loc, "the parsed file is empty"}
+            }));
+    }
+    else if(loc.line() == 1 && loc.region() == 1)
+    {
+        // Here it assumes that top-level table starts at the first character.
+        // The region corresponds to the top-level table will be generated at
+        // `parse_toml_file` function.
+        //     It also assumes that the top-level table size is just one and
+        // the line number is `1`. It is always satisfied. And those conditions
+        // are satisfied only if the table is the top-level table.
+        //
+        // 1. one-character dot-key at the first line
+        // ```toml
+        // a.b = "c"
+        // ```
+        // toml11 counts whole key as the table key. Here, `a.b` is the region
+        // of the table "a". It could be counter intuitive, but it works.
+        // The size of the region is 3, not 1. The above example is the shortest
+        // dot-key example. The size cannot be 1.
+        //
+        // 2. one-character inline-table at the first line
+        // ```toml
+        // a = {b = "c"}
+        // ```
+        // toml11 considers the inline table body as the table region. Here,
+        // `{b = "c"}` is the region of the table "a". The size of the region
+        // is 9, not 1. The shotest inline table still has two characters, `{`
+        // and `}`. The size cannot be 1.
+        //
+        // 3. one-character table declaration at the first line
+        // ```toml
+        // [a]
+        // ```
+        // toml11 considers the whole table key as the table region. Here,
+        // `[a]` is the table region. The size is 3, not 1.
+        //
+        throw std::out_of_range(format_underline(concat_to_string(
+            "key \"", ky, "\" not found in the top-level table"), {
+                {loc, "the top-level table starts here"}
+            }));
+    }
+    else
+    {
+        // normal table.
+        throw std::out_of_range(format_underline(concat_to_string(
+            "key \"", ky, "\" not found"), { {loc, "in this table"} }));
+    }
+}
+
+// switch by `value_t` at the compile time.
+template<value_t T>
+struct switch_cast {};
+#define TOML11_GENERATE_SWITCH_CASTER(TYPE) \
+    template<>                                                           \
+    struct switch_cast<value_t::TYPE>                                    \
+    {                                                                    \
+        template<typename Value>                                         \
+        static typename Value::TYPE##_type& invoke(Value& v)             \
+        {                                                                \
+            return v.as_##TYPE();                                        \
+        }                                                                \
+        template<typename Value>                                         \
+        static typename Value::TYPE##_type const& invoke(const Value& v) \
+        {                                                                \
+            return v.as_##TYPE();                                        \
+        }                                                                \
+        template<typename Value>                                         \
+        static typename Value::TYPE##_type&& invoke(Value&& v)           \
+        {                                                                \
+            return std::move(v).as_##TYPE();                             \
+        }                                                                \
+    };                                                                   \
+    /**/
+TOML11_GENERATE_SWITCH_CASTER(boolean)
+TOML11_GENERATE_SWITCH_CASTER(integer)
+TOML11_GENERATE_SWITCH_CASTER(floating)
+TOML11_GENERATE_SWITCH_CASTER(string)
+TOML11_GENERATE_SWITCH_CASTER(offset_datetime)
+TOML11_GENERATE_SWITCH_CASTER(local_datetime)
+TOML11_GENERATE_SWITCH_CASTER(local_date)
+TOML11_GENERATE_SWITCH_CASTER(local_time)
+TOML11_GENERATE_SWITCH_CASTER(array)
+TOML11_GENERATE_SWITCH_CASTER(table)
+
+#undef TOML11_GENERATE_SWITCH_CASTER
+
+}// detail
+
+template<typename Comment, // discard/preserve_comment
+         template<typename ...> class Table = std::unordered_map,
+         template<typename ...> class Array = std::vector>
+class basic_value
+{
+    template<typename T, typename U>
+    static void assigner(T& dst, U&& v)
+    {
+        const auto tmp = ::new(std::addressof(dst)) T(std::forward<U>(v));
+        assert(tmp == std::addressof(dst));
+        (void)tmp;
+    }
+
+    using region_base = detail::region_base;
+
+    template<typename C, template<typename ...> class T,
+             template<typename ...> class A>
+    friend class basic_value;
+
+  public:
+
+    using comment_type         = Comment;
+    using key_type             = ::toml::key;
+    using value_type           = basic_value<comment_type, Table, Array>;
+    using boolean_type         = ::toml::boolean;
+    using integer_type         = ::toml::integer;
+    using floating_type        = ::toml::floating;
+    using string_type          = ::toml::string;
+    using local_time_type      = ::toml::local_time;
+    using local_date_type      = ::toml::local_date;
+    using local_datetime_type  = ::toml::local_datetime;
+    using offset_datetime_type = ::toml::offset_datetime;
+    using array_type           = Array<value_type>;
+    using table_type           = Table<key_type, value_type>;
+
+  public:
+
+    basic_value() noexcept
+        : type_(value_t::empty),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {}
+    ~basic_value() noexcept {this->cleanup();}
+
+    basic_value(const basic_value& v)
+        : type_(v.type()), region_info_(v.region_info_), comments_(v.comments_)
+    {
+        switch(v.type())
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          : assigner(array_          , v.array_          ); break;
+            case value_t::table          : assigner(table_          , v.table_          ); break;
+            default: break;
+        }
+    }
+    basic_value(basic_value&& v)
+        : type_(v.type()), region_info_(std::move(v.region_info_)),
+          comments_(std::move(v.comments_))
+    {
+        switch(this->type_) // here this->type_ is already initialized
+        {
+            case value_t::boolean        : assigner(boolean_        , std::move(v.boolean_        )); break;
+            case value_t::integer        : assigner(integer_        , std::move(v.integer_        )); break;
+            case value_t::floating       : assigner(floating_       , std::move(v.floating_       )); break;
+            case value_t::string         : assigner(string_         , std::move(v.string_         )); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break;
+            case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break;
+            case value_t::local_date     : assigner(local_date_     , std::move(v.local_date_     )); break;
+            case value_t::local_time     : assigner(local_time_     , std::move(v.local_time_     )); break;
+            case value_t::array          : assigner(array_          , std::move(v.array_          )); break;
+            case value_t::table          : assigner(table_          , std::move(v.table_          )); break;
+            default: break;
+        }
+    }
+    basic_value& operator=(const basic_value& v)
+    {
+        if(this == std::addressof(v)) {return *this;}
+        this->cleanup();
+        this->region_info_ = v.region_info_;
+        this->comments_ = v.comments_;
+        this->type_ = v.type();
+        switch(this->type_)
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          : assigner(array_          , v.array_          ); break;
+            case value_t::table          : assigner(table_          , v.table_          ); break;
+            default: break;
+        }
+        return *this;
+    }
+    basic_value& operator=(basic_value&& v)
+    {
+        if(this == std::addressof(v)) {return *this;}
+        this->cleanup();
+        this->region_info_ = std::move(v.region_info_);
+        this->comments_ = std::move(v.comments_);
+        this->type_ = v.type();
+        switch(this->type_)
+        {
+            case value_t::boolean        : assigner(boolean_        , std::move(v.boolean_        )); break;
+            case value_t::integer        : assigner(integer_        , std::move(v.integer_        )); break;
+            case value_t::floating       : assigner(floating_       , std::move(v.floating_       )); break;
+            case value_t::string         : assigner(string_         , std::move(v.string_         )); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break;
+            case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break;
+            case value_t::local_date     : assigner(local_date_     , std::move(v.local_date_     )); break;
+            case value_t::local_time     : assigner(local_time_     , std::move(v.local_time_     )); break;
+            case value_t::array          : assigner(array_          , std::move(v.array_          )); break;
+            case value_t::table          : assigner(table_          , std::move(v.table_          )); break;
+            default: break;
+        }
+        return *this;
+    }
+
+    // overwrite comments ----------------------------------------------------
+
+    basic_value(const basic_value& v, std::vector<std::string> com)
+        : type_(v.type()), region_info_(v.region_info_),
+          comments_(std::move(com))
+    {
+        switch(v.type())
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          : assigner(array_          , v.array_          ); break;
+            case value_t::table          : assigner(table_          , v.table_          ); break;
+            default: break;
+        }
+    }
+
+    basic_value(basic_value&& v, std::vector<std::string> com)
+        : type_(v.type()), region_info_(std::move(v.region_info_)),
+          comments_(std::move(com))
+    {
+        switch(this->type_) // here this->type_ is already initialized
+        {
+            case value_t::boolean        : assigner(boolean_        , std::move(v.boolean_        )); break;
+            case value_t::integer        : assigner(integer_        , std::move(v.integer_        )); break;
+            case value_t::floating       : assigner(floating_       , std::move(v.floating_       )); break;
+            case value_t::string         : assigner(string_         , std::move(v.string_         )); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break;
+            case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break;
+            case value_t::local_date     : assigner(local_date_     , std::move(v.local_date_     )); break;
+            case value_t::local_time     : assigner(local_time_     , std::move(v.local_time_     )); break;
+            case value_t::array          : assigner(array_          , std::move(v.array_          )); break;
+            case value_t::table          : assigner(table_          , std::move(v.table_          )); break;
+            default: break;
+        }
+    }
+
+    // -----------------------------------------------------------------------
+    // conversion between different basic_values.
+    template<typename C,
+             template<typename ...> class T,
+             template<typename ...> class A>
+    basic_value(const basic_value<C, T, A>& v)
+        : type_(v.type()), region_info_(v.region_info_), comments_(v.comments())
+    {
+        switch(v.type())
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          :
+            {
+                array_type tmp(v.as_array(std::nothrow).begin(),
+                               v.as_array(std::nothrow).end());
+                assigner(array_, std::move(tmp));
+                break;
+            }
+            case value_t::table          :
+            {
+                table_type tmp(v.as_table(std::nothrow).begin(),
+                               v.as_table(std::nothrow).end());
+                assigner(table_, std::move(tmp));
+                break;
+            }
+            default: break;
+        }
+    }
+    template<typename C,
+             template<typename ...> class T,
+             template<typename ...> class A>
+    basic_value(const basic_value<C, T, A>& v, std::vector<std::string> com)
+        : type_(v.type()), region_info_(v.region_info_),
+          comments_(std::move(com))
+    {
+        switch(v.type())
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          :
+            {
+                array_type tmp(v.as_array(std::nothrow).begin(),
+                               v.as_array(std::nothrow).end());
+                assigner(array_, std::move(tmp));
+                break;
+            }
+            case value_t::table          :
+            {
+                table_type tmp(v.as_table(std::nothrow).begin(),
+                               v.as_table(std::nothrow).end());
+                assigner(table_, std::move(tmp));
+                break;
+            }
+            default: break;
+        }
+    }
+    template<typename C,
+             template<typename ...> class T,
+             template<typename ...> class A>
+    basic_value& operator=(const basic_value<C, T, A>& v)
+    {
+        this->region_info_ = v.region_info_;
+        this->comments_    = comment_type(v.comments());
+        this->type_        = v.type();
+        switch(v.type())
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          :
+            {
+                array_type tmp(v.as_array(std::nothrow).begin(),
+                               v.as_array(std::nothrow).end());
+                assigner(array_, std::move(tmp));
+                break;
+            }
+            case value_t::table          :
+            {
+                table_type tmp(v.as_table(std::nothrow).begin(),
+                               v.as_table(std::nothrow).end());
+                assigner(table_, std::move(tmp));
+                break;
+            }
+            default: break;
+        }
+        return *this;
+    }
+
+    // boolean ==============================================================
+
+    basic_value(boolean b)
+        : type_(value_t::boolean),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->boolean_, b);
+    }
+    basic_value& operator=(boolean b)
+    {
+        this->cleanup();
+        this->type_ = value_t::boolean;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->boolean_, b);
+        return *this;
+    }
+    basic_value(boolean b, std::vector<std::string> com)
+        : type_(value_t::boolean),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->boolean_, b);
+    }
+
+    // integer ==============================================================
+
+    template<typename T, typename std::enable_if<detail::conjunction<
+        std::is_integral<T>, detail::negation<std::is_same<T, boolean>>>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value(T i)
+        : type_(value_t::integer),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->integer_, static_cast<integer>(i));
+    }
+
+    template<typename T, typename std::enable_if<detail::conjunction<
+        std::is_integral<T>, detail::negation<std::is_same<T, boolean>>>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value& operator=(T i)
+    {
+        this->cleanup();
+        this->type_ = value_t::integer;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->integer_, static_cast<integer>(i));
+        return *this;
+    }
+
+    template<typename T, typename std::enable_if<detail::conjunction<
+        std::is_integral<T>, detail::negation<std::is_same<T, boolean>>>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value(T i, std::vector<std::string> com)
+        : type_(value_t::integer),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->integer_, static_cast<integer>(i));
+    }
+
+    // floating =============================================================
+
+    template<typename T, typename std::enable_if<
+        std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value(T f)
+        : type_(value_t::floating),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->floating_, static_cast<floating>(f));
+    }
+
+
+    template<typename T, typename std::enable_if<
+        std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value& operator=(T f)
+    {
+        this->cleanup();
+        this->type_ = value_t::floating;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->floating_, static_cast<floating>(f));
+        return *this;
+    }
+
+    template<typename T, typename std::enable_if<
+        std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value(T f, std::vector<std::string> com)
+        : type_(value_t::floating),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->floating_, f);
+    }
+
+    // string ===============================================================
+
+    basic_value(toml::string s)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, std::move(s));
+    }
+    basic_value& operator=(toml::string s)
+    {
+        this->cleanup();
+        this->type_ = value_t::string ;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->string_, s);
+        return *this;
+    }
+    basic_value(toml::string s, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, std::move(s));
+    }
+
+    basic_value(std::string s)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(std::move(s)));
+    }
+    basic_value& operator=(std::string s)
+    {
+        this->cleanup();
+        this->type_ = value_t::string ;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->string_, toml::string(std::move(s)));
+        return *this;
+    }
+    basic_value(std::string s, string_t kind)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(std::move(s), kind));
+    }
+    basic_value(std::string s, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(std::move(s)));
+    }
+    basic_value(std::string s, string_t kind, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(std::move(s), kind));
+    }
+
+    basic_value(const char* s)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(std::string(s)));
+    }
+    basic_value& operator=(const char* s)
+    {
+        this->cleanup();
+        this->type_ = value_t::string ;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->string_, toml::string(std::string(s)));
+        return *this;
+    }
+    basic_value(const char* s, string_t kind)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(std::string(s), kind));
+    }
+    basic_value(const char* s, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(std::string(s)));
+    }
+    basic_value(const char* s, string_t kind, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(std::string(s), kind));
+    }
+
+#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
+    basic_value(std::string_view s)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(s));
+    }
+    basic_value& operator=(std::string_view s)
+    {
+        this->cleanup();
+        this->type_ = value_t::string ;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->string_, toml::string(s));
+        return *this;
+    }
+    basic_value(std::string_view s, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(s));
+    }
+    basic_value(std::string_view s, string_t kind)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(s, kind));
+    }
+    basic_value(std::string_view s, string_t kind, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(s, kind));
+    }
+#endif
+
+    // local date ===========================================================
+
+    basic_value(const local_date& ld)
+        : type_(value_t::local_date),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->local_date_, ld);
+    }
+    basic_value& operator=(const local_date& ld)
+    {
+        this->cleanup();
+        this->type_ = value_t::local_date;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->local_date_, ld);
+        return *this;
+    }
+    basic_value(const local_date& ld, std::vector<std::string> com)
+        : type_(value_t::local_date),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->local_date_, ld);
+    }
+
+    // local time ===========================================================
+
+    basic_value(const local_time& lt)
+        : type_(value_t::local_time),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->local_time_, lt);
+    }
+    basic_value(const local_time& lt, std::vector<std::string> com)
+        : type_(value_t::local_time),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->local_time_, lt);
+    }
+    basic_value& operator=(const local_time& lt)
+    {
+        this->cleanup();
+        this->type_ = value_t::local_time;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->local_time_, lt);
+        return *this;
+    }
+
+    template<typename Rep, typename Period>
+    basic_value(const std::chrono::duration<Rep, Period>& dur)
+        : type_(value_t::local_time),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->local_time_, local_time(dur));
+    }
+    template<typename Rep, typename Period>
+    basic_value(const std::chrono::duration<Rep, Period>& dur,
+                std::vector<std::string> com)
+        : type_(value_t::local_time),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->local_time_, local_time(dur));
+    }
+    template<typename Rep, typename Period>
+    basic_value& operator=(const std::chrono::duration<Rep, Period>& dur)
+    {
+        this->cleanup();
+        this->type_ = value_t::local_time;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->local_time_, local_time(dur));
+        return *this;
+    }
+
+    // local datetime =======================================================
+
+    basic_value(const local_datetime& ldt)
+        : type_(value_t::local_datetime),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->local_datetime_, ldt);
+    }
+    basic_value(const local_datetime& ldt, std::vector<std::string> com)
+        : type_(value_t::local_datetime),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->local_datetime_, ldt);
+    }
+    basic_value& operator=(const local_datetime& ldt)
+    {
+        this->cleanup();
+        this->type_ = value_t::local_datetime;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->local_datetime_, ldt);
+        return *this;
+    }
+
+    // offset datetime ======================================================
+
+    basic_value(const offset_datetime& odt)
+        : type_(value_t::offset_datetime),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->offset_datetime_, odt);
+    }
+    basic_value(const offset_datetime& odt, std::vector<std::string> com)
+        : type_(value_t::offset_datetime),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->offset_datetime_, odt);
+    }
+    basic_value& operator=(const offset_datetime& odt)
+    {
+        this->cleanup();
+        this->type_ = value_t::offset_datetime;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->offset_datetime_, odt);
+        return *this;
+    }
+    basic_value(const std::chrono::system_clock::time_point& tp)
+        : type_(value_t::offset_datetime),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->offset_datetime_, offset_datetime(tp));
+    }
+    basic_value(const std::chrono::system_clock::time_point& tp,
+                std::vector<std::string> com)
+        : type_(value_t::offset_datetime),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->offset_datetime_, offset_datetime(tp));
+    }
+    basic_value& operator=(const std::chrono::system_clock::time_point& tp)
+    {
+        this->cleanup();
+        this->type_ = value_t::offset_datetime;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->offset_datetime_, offset_datetime(tp));
+        return *this;
+    }
+
+    // array ================================================================
+
+    basic_value(const array_type& ary)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->array_, ary);
+    }
+    basic_value(const array_type& ary, std::vector<std::string> com)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->array_, ary);
+    }
+    basic_value& operator=(const array_type& ary)
+    {
+        this->cleanup();
+        this->type_ = value_t::array ;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->array_, ary);
+        return *this;
+    }
+
+    // array (initializer_list) ----------------------------------------------
+
+    template<typename T, typename std::enable_if<
+            std::is_convertible<T, value_type>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value(std::initializer_list<T> list)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        array_type ary(list.begin(), list.end());
+        assigner(this->array_, std::move(ary));
+    }
+    template<typename T, typename std::enable_if<
+            std::is_convertible<T, value_type>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value(std::initializer_list<T> list, std::vector<std::string> com)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        array_type ary(list.begin(), list.end());
+        assigner(this->array_, std::move(ary));
+    }
+    template<typename T, typename std::enable_if<
+            std::is_convertible<T, value_type>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value& operator=(std::initializer_list<T> list)
+    {
+        this->cleanup();
+        this->type_ = value_t::array;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+
+        array_type ary(list.begin(), list.end());
+        assigner(this->array_, std::move(ary));
+        return *this;
+    }
+
+    // array (STL Containers) ------------------------------------------------
+
+    template<typename T, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<T, array_type>>,
+            detail::is_container<T>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value(const T& list)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        static_assert(std::is_convertible<typename T::value_type, value_type>::value,
+            "elements of a container should be convertible to toml::value");
+
+        array_type ary(list.size());
+        std::copy(list.begin(), list.end(), ary.begin());
+        assigner(this->array_, std::move(ary));
+    }
+    template<typename T, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<T, array_type>>,
+            detail::is_container<T>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value(const T& list, std::vector<std::string> com)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        static_assert(std::is_convertible<typename T::value_type, value_type>::value,
+            "elements of a container should be convertible to toml::value");
+
+        array_type ary(list.size());
+        std::copy(list.begin(), list.end(), ary.begin());
+        assigner(this->array_, std::move(ary));
+    }
+    template<typename T, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<T, array_type>>,
+            detail::is_container<T>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value& operator=(const T& list)
+    {
+        static_assert(std::is_convertible<typename T::value_type, value_type>::value,
+            "elements of a container should be convertible to toml::value");
+
+        this->cleanup();
+        this->type_ = value_t::array;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+
+        array_type ary(list.size());
+        std::copy(list.begin(), list.end(), ary.begin());
+        assigner(this->array_, std::move(ary));
+        return *this;
+    }
+
+    // table ================================================================
+
+    basic_value(const table_type& tab)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->table_, tab);
+    }
+    basic_value(const table_type& tab, std::vector<std::string> com)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->table_, tab);
+    }
+    basic_value& operator=(const table_type& tab)
+    {
+        this->cleanup();
+        this->type_ = value_t::table;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->table_, tab);
+        return *this;
+    }
+
+    // initializer-list ------------------------------------------------------
+
+    basic_value(std::initializer_list<std::pair<key, basic_value>> list)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        table_type tab;
+        for(const auto& elem : list) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+    }
+
+    basic_value(std::initializer_list<std::pair<key, basic_value>> list,
+                std::vector<std::string> com)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        table_type tab;
+        for(const auto& elem : list) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+    }
+    basic_value& operator=(std::initializer_list<std::pair<key, basic_value>> list)
+    {
+        this->cleanup();
+        this->type_ = value_t::table;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+
+        table_type tab;
+        for(const auto& elem : list) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+        return *this;
+    }
+
+    // other table-like -----------------------------------------------------
+
+    template<typename Map, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<Map, table_type>>,
+            detail::is_map<Map>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value(const Map& mp)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        table_type tab;
+        for(const auto& elem : mp) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+    }
+    template<typename Map, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<Map, table_type>>,
+            detail::is_map<Map>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value(const Map& mp, std::vector<std::string> com)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        table_type tab;
+        for(const auto& elem : mp) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+    }
+    template<typename Map, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<Map, table_type>>,
+            detail::is_map<Map>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value& operator=(const Map& mp)
+    {
+        this->cleanup();
+        this->type_ = value_t::table;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+
+        table_type tab;
+        for(const auto& elem : mp) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+        return *this;
+    }
+
+    // user-defined =========================================================
+
+    // convert using into_toml() method -------------------------------------
+
+    template<typename T, typename std::enable_if<
+        detail::has_into_toml_method<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value(const T& ud): basic_value(ud.into_toml()) {}
+
+    template<typename T, typename std::enable_if<
+        detail::has_into_toml_method<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value(const T& ud, std::vector<std::string> com)
+        : basic_value(ud.into_toml(), std::move(com))
+    {}
+    template<typename T, typename std::enable_if<
+        detail::has_into_toml_method<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value& operator=(const T& ud)
+    {
+        *this = ud.into_toml();
+        return *this;
+    }
+
+    // convert using into<T> struct -----------------------------------------
+
+    template<typename T, std::size_t S = sizeof(::toml::into<T>)>
+    basic_value(const T& ud): basic_value(::toml::into<T>::into_toml(ud)) {}
+    template<typename T, std::size_t S = sizeof(::toml::into<T>)>
+    basic_value(const T& ud, std::vector<std::string> com)
+        : basic_value(::toml::into<T>::into_toml(ud), std::move(com))
+    {}
+    template<typename T, std::size_t S = sizeof(::toml::into<T>)>
+    basic_value& operator=(const T& ud)
+    {
+        *this = ::toml::into<T>::into_toml(ud);
+        return *this;
+    }
+
+    // for internal use ------------------------------------------------------
+    //
+    // Those constructors take detail::region that contains parse result.
+
+    basic_value(boolean b, detail::region reg, std::vector<std::string> cm)
+        : type_(value_t::boolean),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->boolean_, b);
+    }
+    template<typename T, typename std::enable_if<
+        detail::conjunction<
+            std::is_integral<T>, detail::negation<std::is_same<T, boolean>>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value(T i, detail::region reg, std::vector<std::string> cm)
+        : type_(value_t::integer),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->integer_, static_cast<integer>(i));
+    }
+    template<typename T, typename std::enable_if<
+        std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value(T f, detail::region reg, std::vector<std::string> cm)
+        : type_(value_t::floating),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->floating_, static_cast<floating>(f));
+    }
+    basic_value(toml::string s, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::string),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->string_, std::move(s));
+    }
+    basic_value(const local_date& ld, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::local_date),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->local_date_, ld);
+    }
+    basic_value(const local_time& lt, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::local_time),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->local_time_, lt);
+    }
+    basic_value(const local_datetime& ldt, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::local_datetime),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->local_datetime_, ldt);
+    }
+    basic_value(const offset_datetime& odt, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::offset_datetime),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->offset_datetime_, odt);
+    }
+    basic_value(const array_type& ary, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::array),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->array_, ary);
+    }
+    basic_value(const table_type& tab, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::table),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->table_, tab);
+    }
+
+    template<typename T, typename std::enable_if<
+        detail::is_exact_toml_type<T, value_type>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value(std::pair<T, detail::region> parse_result, std::vector<std::string> com)
+        : basic_value(std::move(parse_result.first),
+                      std::move(parse_result.second),
+                      std::move(com))
+    {}
+
+    // type checking and casting ============================================
+
+    template<typename T, typename std::enable_if<
+        detail::is_exact_toml_type<T, value_type>::value,
+        std::nullptr_t>::type = nullptr>
+    bool is() const noexcept
+    {
+        return detail::type_to_enum<T, value_type>::value == this->type_;
+    }
+    bool is(value_t t) const noexcept {return t == this->type_;}
+
+    bool is_uninitialized()   const noexcept {return this->is(value_t::empty          );}
+    bool is_boolean()         const noexcept {return this->is(value_t::boolean        );}
+    bool is_integer()         const noexcept {return this->is(value_t::integer        );}
+    bool is_floating()        const noexcept {return this->is(value_t::floating       );}
+    bool is_string()          const noexcept {return this->is(value_t::string         );}
+    bool is_offset_datetime() const noexcept {return this->is(value_t::offset_datetime);}
+    bool is_local_datetime()  const noexcept {return this->is(value_t::local_datetime );}
+    bool is_local_date()      const noexcept {return this->is(value_t::local_date     );}
+    bool is_local_time()      const noexcept {return this->is(value_t::local_time     );}
+    bool is_array()           const noexcept {return this->is(value_t::array          );}
+    bool is_table()           const noexcept {return this->is(value_t::table          );}
+
+    value_t type() const noexcept {return type_;}
+
+    template<value_t T>
+    typename detail::enum_to_type<T, value_type>::type&       cast() &
+    {
+        if(this->type_ != T)
+        {
+            detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
+        }
+        return detail::switch_cast<T>::invoke(*this);
+    }
+    template<value_t T>
+    typename detail::enum_to_type<T, value_type>::type const& cast() const&
+    {
+        if(this->type_ != T)
+        {
+            detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
+        }
+        return detail::switch_cast<T>::invoke(*this);
+    }
+    template<value_t T>
+    typename detail::enum_to_type<T, value_type>::type&&      cast() &&
+    {
+        if(this->type_ != T)
+        {
+            detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
+        }
+        return detail::switch_cast<T>::invoke(std::move(*this));
+    }
+
+    // ------------------------------------------------------------------------
+    // nothrow version
+
+    boolean         const& as_boolean        (const std::nothrow_t&) const& noexcept {return this->boolean_;}
+    integer         const& as_integer        (const std::nothrow_t&) const& noexcept {return this->integer_;}
+    floating        const& as_floating       (const std::nothrow_t&) const& noexcept {return this->floating_;}
+    string          const& as_string         (const std::nothrow_t&) const& noexcept {return this->string_;}
+    offset_datetime const& as_offset_datetime(const std::nothrow_t&) const& noexcept {return this->offset_datetime_;}
+    local_datetime  const& as_local_datetime (const std::nothrow_t&) const& noexcept {return this->local_datetime_;}
+    local_date      const& as_local_date     (const std::nothrow_t&) const& noexcept {return this->local_date_;}
+    local_time      const& as_local_time     (const std::nothrow_t&) const& noexcept {return this->local_time_;}
+    array_type      const& as_array          (const std::nothrow_t&) const& noexcept {return this->array_.value();}
+    table_type      const& as_table          (const std::nothrow_t&) const& noexcept {return this->table_.value();}
+
+    boolean        & as_boolean        (const std::nothrow_t&) & noexcept {return this->boolean_;}
+    integer        & as_integer        (const std::nothrow_t&) & noexcept {return this->integer_;}
+    floating       & as_floating       (const std::nothrow_t&) & noexcept {return this->floating_;}
+    string         & as_string         (const std::nothrow_t&) & noexcept {return this->string_;}
+    offset_datetime& as_offset_datetime(const std::nothrow_t&) & noexcept {return this->offset_datetime_;}
+    local_datetime & as_local_datetime (const std::nothrow_t&) & noexcept {return this->local_datetime_;}
+    local_date     & as_local_date     (const std::nothrow_t&) & noexcept {return this->local_date_;}
+    local_time     & as_local_time     (const std::nothrow_t&) & noexcept {return this->local_time_;}
+    array_type     & as_array          (const std::nothrow_t&) & noexcept {return this->array_.value();}
+    table_type     & as_table          (const std::nothrow_t&) & noexcept {return this->table_.value();}
+
+    boolean        && as_boolean        (const std::nothrow_t&) && noexcept {return std::move(this->boolean_);}
+    integer        && as_integer        (const std::nothrow_t&) && noexcept {return std::move(this->integer_);}
+    floating       && as_floating       (const std::nothrow_t&) && noexcept {return std::move(this->floating_);}
+    string         && as_string         (const std::nothrow_t&) && noexcept {return std::move(this->string_);}
+    offset_datetime&& as_offset_datetime(const std::nothrow_t&) && noexcept {return std::move(this->offset_datetime_);}
+    local_datetime && as_local_datetime (const std::nothrow_t&) && noexcept {return std::move(this->local_datetime_);}
+    local_date     && as_local_date     (const std::nothrow_t&) && noexcept {return std::move(this->local_date_);}
+    local_time     && as_local_time     (const std::nothrow_t&) && noexcept {return std::move(this->local_time_);}
+    array_type     && as_array          (const std::nothrow_t&) && noexcept {return std::move(this->array_.value());}
+    table_type     && as_table          (const std::nothrow_t&) && noexcept {return std::move(this->table_.value());}
+
+    // ========================================================================
+    // throw version
+    // ------------------------------------------------------------------------
+    // const reference {{{
+
+    boolean const& as_boolean() const&
+    {
+        if(this->type_ != value_t::boolean)
+        {
+            detail::throw_bad_cast<value_t::boolean>(
+                    "toml::value::as_boolean(): ", this->type_, *this);
+        }
+        return this->boolean_;
+    }
+    integer const& as_integer() const&
+    {
+        if(this->type_ != value_t::integer)
+        {
+            detail::throw_bad_cast<value_t::integer>(
+                    "toml::value::as_integer(): ", this->type_, *this);
+        }
+        return this->integer_;
+    }
+    floating const& as_floating() const&
+    {
+        if(this->type_ != value_t::floating)
+        {
+            detail::throw_bad_cast<value_t::floating>(
+                    "toml::value::as_floating(): ", this->type_, *this);
+        }
+        return this->floating_;
+    }
+    string const& as_string() const&
+    {
+        if(this->type_ != value_t::string)
+        {
+            detail::throw_bad_cast<value_t::string>(
+                    "toml::value::as_string(): ", this->type_, *this);
+        }
+        return this->string_;
+    }
+    offset_datetime const& as_offset_datetime() const&
+    {
+        if(this->type_ != value_t::offset_datetime)
+        {
+            detail::throw_bad_cast<value_t::offset_datetime>(
+                    "toml::value::as_offset_datetime(): ", this->type_, *this);
+        }
+        return this->offset_datetime_;
+    }
+    local_datetime const& as_local_datetime() const&
+    {
+        if(this->type_ != value_t::local_datetime)
+        {
+            detail::throw_bad_cast<value_t::local_datetime>(
+                    "toml::value::as_local_datetime(): ", this->type_, *this);
+        }
+        return this->local_datetime_;
+    }
+    local_date const& as_local_date() const&
+    {
+        if(this->type_ != value_t::local_date)
+        {
+            detail::throw_bad_cast<value_t::local_date>(
+                    "toml::value::as_local_date(): ", this->type_, *this);
+        }
+        return this->local_date_;
+    }
+    local_time const& as_local_time() const&
+    {
+        if(this->type_ != value_t::local_time)
+        {
+            detail::throw_bad_cast<value_t::local_time>(
+                    "toml::value::as_local_time(): ", this->type_, *this);
+        }
+        return this->local_time_;
+    }
+    array_type const& as_array() const&
+    {
+        if(this->type_ != value_t::array)
+        {
+            detail::throw_bad_cast<value_t::array>(
+                    "toml::value::as_array(): ", this->type_, *this);
+        }
+        return this->array_.value();
+    }
+    table_type const& as_table() const&
+    {
+        if(this->type_ != value_t::table)
+        {
+            detail::throw_bad_cast<value_t::table>(
+                    "toml::value::as_table(): ", this->type_, *this);
+        }
+        return this->table_.value();
+    }
+    // }}}
+    // ------------------------------------------------------------------------
+    // nonconst reference {{{
+
+    boolean & as_boolean() &
+    {
+        if(this->type_ != value_t::boolean)
+        {
+            detail::throw_bad_cast<value_t::boolean>(
+                    "toml::value::as_boolean(): ", this->type_, *this);
+        }
+        return this->boolean_;
+    }
+    integer & as_integer() &
+    {
+        if(this->type_ != value_t::integer)
+        {
+            detail::throw_bad_cast<value_t::integer>(
+                    "toml::value::as_integer(): ", this->type_, *this);
+        }
+        return this->integer_;
+    }
+    floating & as_floating() &
+    {
+        if(this->type_ != value_t::floating)
+        {
+            detail::throw_bad_cast<value_t::floating>(
+                    "toml::value::as_floating(): ", this->type_, *this);
+        }
+        return this->floating_;
+    }
+    string & as_string() &
+    {
+        if(this->type_ != value_t::string)
+        {
+            detail::throw_bad_cast<value_t::string>(
+                    "toml::value::as_string(): ", this->type_, *this);
+        }
+        return this->string_;
+    }
+    offset_datetime & as_offset_datetime() &
+    {
+        if(this->type_ != value_t::offset_datetime)
+        {
+            detail::throw_bad_cast<value_t::offset_datetime>(
+                    "toml::value::as_offset_datetime(): ", this->type_, *this);
+        }
+        return this->offset_datetime_;
+    }
+    local_datetime & as_local_datetime() &
+    {
+        if(this->type_ != value_t::local_datetime)
+        {
+            detail::throw_bad_cast<value_t::local_datetime>(
+                    "toml::value::as_local_datetime(): ", this->type_, *this);
+        }
+        return this->local_datetime_;
+    }
+    local_date & as_local_date() &
+    {
+        if(this->type_ != value_t::local_date)
+        {
+            detail::throw_bad_cast<value_t::local_date>(
+                    "toml::value::as_local_date(): ", this->type_, *this);
+        }
+        return this->local_date_;
+    }
+    local_time & as_local_time() &
+    {
+        if(this->type_ != value_t::local_time)
+        {
+            detail::throw_bad_cast<value_t::local_time>(
+                    "toml::value::as_local_time(): ", this->type_, *this);
+        }
+        return this->local_time_;
+    }
+    array_type & as_array() &
+    {
+        if(this->type_ != value_t::array)
+        {
+            detail::throw_bad_cast<value_t::array>(
+                    "toml::value::as_array(): ", this->type_, *this);
+        }
+        return this->array_.value();
+    }
+    table_type & as_table() &
+    {
+        if(this->type_ != value_t::table)
+        {
+            detail::throw_bad_cast<value_t::table>(
+                    "toml::value::as_table(): ", this->type_, *this);
+        }
+        return this->table_.value();
+    }
+
+    // }}}
+    // ------------------------------------------------------------------------
+    // rvalue reference {{{
+
+    boolean && as_boolean() &&
+    {
+        if(this->type_ != value_t::boolean)
+        {
+            detail::throw_bad_cast<value_t::boolean>(
+                    "toml::value::as_boolean(): ", this->type_, *this);
+        }
+        return std::move(this->boolean_);
+    }
+    integer && as_integer() &&
+    {
+        if(this->type_ != value_t::integer)
+        {
+            detail::throw_bad_cast<value_t::integer>(
+                    "toml::value::as_integer(): ", this->type_, *this);
+        }
+        return std::move(this->integer_);
+    }
+    floating && as_floating() &&
+    {
+        if(this->type_ != value_t::floating)
+        {
+            detail::throw_bad_cast<value_t::floating>(
+                    "toml::value::as_floating(): ", this->type_, *this);
+        }
+        return std::move(this->floating_);
+    }
+    string && as_string() &&
+    {
+        if(this->type_ != value_t::string)
+        {
+            detail::throw_bad_cast<value_t::string>(
+                    "toml::value::as_string(): ", this->type_, *this);
+        }
+        return std::move(this->string_);
+    }
+    offset_datetime && as_offset_datetime() &&
+    {
+        if(this->type_ != value_t::offset_datetime)
+        {
+            detail::throw_bad_cast<value_t::offset_datetime>(
+                    "toml::value::as_offset_datetime(): ", this->type_, *this);
+        }
+        return std::move(this->offset_datetime_);
+    }
+    local_datetime && as_local_datetime() &&
+    {
+        if(this->type_ != value_t::local_datetime)
+        {
+            detail::throw_bad_cast<value_t::local_datetime>(
+                    "toml::value::as_local_datetime(): ", this->type_, *this);
+        }
+        return std::move(this->local_datetime_);
+    }
+    local_date && as_local_date() &&
+    {
+        if(this->type_ != value_t::local_date)
+        {
+            detail::throw_bad_cast<value_t::local_date>(
+                    "toml::value::as_local_date(): ", this->type_, *this);
+        }
+        return std::move(this->local_date_);
+    }
+    local_time && as_local_time() &&
+    {
+        if(this->type_ != value_t::local_time)
+        {
+            detail::throw_bad_cast<value_t::local_time>(
+                    "toml::value::as_local_time(): ", this->type_, *this);
+        }
+        return std::move(this->local_time_);
+    }
+    array_type && as_array() &&
+    {
+        if(this->type_ != value_t::array)
+        {
+            detail::throw_bad_cast<value_t::array>(
+                    "toml::value::as_array(): ", this->type_, *this);
+        }
+        return std::move(this->array_.value());
+    }
+    table_type && as_table() &&
+    {
+        if(this->type_ != value_t::table)
+        {
+            detail::throw_bad_cast<value_t::table>(
+                    "toml::value::as_table(): ", this->type_, *this);
+        }
+        return std::move(this->table_.value());
+    }
+    // }}}
+
+    // accessors =============================================================
+    //
+    // may throw type_error or out_of_range
+    //
+    value_type&       at(const key& k)
+    {
+        if(!this->is_table())
+        {
+            detail::throw_bad_cast<value_t::table>(
+                "toml::value::at(key): ", this->type_, *this);
+        }
+        if(this->as_table(std::nothrow).count(k) == 0)
+        {
+            detail::throw_key_not_found_error(*this, k);
+        }
+        return this->as_table(std::nothrow).at(k);
+    }
+    value_type const& at(const key& k) const
+    {
+        if(!this->is_table())
+        {
+            detail::throw_bad_cast<value_t::table>(
+                "toml::value::at(key): ", this->type_, *this);
+        }
+        if(this->as_table(std::nothrow).count(k) == 0)
+        {
+            detail::throw_key_not_found_error(*this, k);
+        }
+        return this->as_table(std::nothrow).at(k);
+    }
+    value_type&       operator[](const key& k)
+    {
+        if(this->is_uninitialized())
+        {
+            *this = table_type{};
+        }
+        else if(!this->is_table()) // initialized, but not a table
+        {
+            detail::throw_bad_cast<value_t::table>(
+                "toml::value::operator[](key): ", this->type_, *this);
+        }
+        return this->as_table(std::nothrow)[k];
+    }
+
+    value_type&       at(const std::size_t idx)
+    {
+        if(!this->is_array())
+        {
+            detail::throw_bad_cast<value_t::array>(
+                "toml::value::at(idx): ", this->type_, *this);
+        }
+        if(this->as_array(std::nothrow).size() <= idx)
+        {
+            throw std::out_of_range(detail::format_underline(
+                "toml::value::at(idx): no element corresponding to the index", {
+                    {this->location(), concat_to_string("the length is ",
+                        this->as_array(std::nothrow).size(),
+                        ", and the specified index is ", idx)}
+                }));
+        }
+        return this->as_array().at(idx);
+    }
+    value_type const& at(const std::size_t idx) const
+    {
+        if(!this->is_array())
+        {
+            detail::throw_bad_cast<value_t::array>(
+                "toml::value::at(idx): ", this->type_, *this);
+        }
+        if(this->as_array(std::nothrow).size() <= idx)
+        {
+            throw std::out_of_range(detail::format_underline(
+                "toml::value::at(idx): no element corresponding to the index", {
+                    {this->location(), concat_to_string("the length is ",
+                        this->as_array(std::nothrow).size(),
+                        ", and the specified index is ", idx)}
+                }));
+        }
+        return this->as_array(std::nothrow).at(idx);
+    }
+
+    value_type&       operator[](const std::size_t idx) noexcept
+    {
+        // no check...
+        return this->as_array(std::nothrow)[idx];
+    }
+    value_type const& operator[](const std::size_t idx) const noexcept
+    {
+        // no check...
+        return this->as_array(std::nothrow)[idx];
+    }
+
+    void push_back(const value_type& x)
+    {
+        if(!this->is_array())
+        {
+            detail::throw_bad_cast<value_t::array>(
+                "toml::value::push_back(value): ", this->type_, *this);
+        }
+        this->as_array(std::nothrow).push_back(x);
+        return;
+    }
+    void push_back(value_type&& x)
+    {
+        if(!this->is_array())
+        {
+            detail::throw_bad_cast<value_t::array>(
+                "toml::value::push_back(value): ", this->type_, *this);
+        }
+        this->as_array(std::nothrow).push_back(std::move(x));
+        return;
+    }
+
+    template<typename ... Ts>
+    value_type& emplace_back(Ts&& ... args)
+    {
+        if(!this->is_array())
+        {
+            detail::throw_bad_cast<value_t::array>(
+                "toml::value::emplace_back(...): ", this->type_, *this);
+        }
+        this->as_array(std::nothrow).emplace_back(std::forward<Ts>(args) ...);
+        return this->as_array(std::nothrow).back();
+    }
+
+    std::size_t size() const
+    {
+        switch(this->type_)
+        {
+            case value_t::array:
+            {
+                return this->as_array(std::nothrow).size();
+            }
+            case value_t::table:
+            {
+                return this->as_table(std::nothrow).size();
+            }
+            case value_t::string:
+            {
+                return this->as_string(std::nothrow).str.size();
+            }
+            default:
+            {
+                throw type_error(detail::format_underline(
+                    "toml::value::size(): bad_cast to container types", {
+                        {this->location(),
+                         concat_to_string("the actual type is ", this->type_)}
+                    }), this->location());
+            }
+        }
+    }
+
+    std::size_t count(const key_type& k) const
+    {
+        if(!this->is_table())
+        {
+            detail::throw_bad_cast<value_t::table>(
+                "toml::value::count(key): ", this->type_, *this);
+        }
+        return this->as_table(std::nothrow).count(k);
+    }
+
+    bool contains(const key_type& k) const
+    {
+        if(!this->is_table())
+        {
+            detail::throw_bad_cast<value_t::table>(
+                "toml::value::contains(key): ", this->type_, *this);
+        }
+        return (this->as_table(std::nothrow).count(k) != 0);
+    }
+
+    source_location location() const
+    {
+        return source_location(this->region_info_.get());
+    }
+
+    comment_type const& comments() const noexcept {return this->comments_;}
+    comment_type&       comments()       noexcept {return this->comments_;}
+
+  private:
+
+    void cleanup() noexcept
+    {
+        switch(this->type_)
+        {
+            case value_t::string : {string_.~string();       return;}
+            case value_t::array  : {array_.~array_storage(); return;}
+            case value_t::table  : {table_.~table_storage(); return;}
+            default              : return;
+        }
+    }
+
+    // for error messages
+    template<typename Value>
+    friend region_base const* detail::get_region(const Value& v);
+
+    template<typename Value>
+    friend void detail::change_region(Value& v, detail::region reg);
+
+  private:
+
+    using array_storage = detail::storage<array_type>;
+    using table_storage = detail::storage<table_type>;
+
+    value_t type_;
+    union
+    {
+        boolean         boolean_;
+        integer         integer_;
+        floating        floating_;
+        string          string_;
+        offset_datetime offset_datetime_;
+        local_datetime  local_datetime_;
+        local_date      local_date_;
+        local_time      local_time_;
+        array_storage   array_;
+        table_storage   table_;
+    };
+    std::shared_ptr<region_base> region_info_;
+    comment_type                 comments_;
+};
+
+// default toml::value and default array/table.
+// TOML11_DEFAULT_COMMENT_STRATEGY is defined in comments.hpp
+using value = basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>;
+using array = typename value::array_type;
+using table = typename value::table_type;
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+inline bool
+operator==(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    if(lhs.type()     != rhs.type())     {return false;}
+    if(lhs.comments() != rhs.comments()) {return false;}
+
+    switch(lhs.type())
+    {
+        case value_t::boolean  :
+        {
+            return lhs.as_boolean() == rhs.as_boolean();
+        }
+        case value_t::integer  :
+        {
+            return lhs.as_integer() == rhs.as_integer();
+        }
+        case value_t::floating :
+        {
+            return lhs.as_floating() == rhs.as_floating();
+        }
+        case value_t::string   :
+        {
+            return lhs.as_string() == rhs.as_string();
+        }
+        case value_t::offset_datetime:
+        {
+            return lhs.as_offset_datetime() == rhs.as_offset_datetime();
+        }
+        case value_t::local_datetime:
+        {
+            return lhs.as_local_datetime() == rhs.as_local_datetime();
+        }
+        case value_t::local_date:
+        {
+            return lhs.as_local_date() == rhs.as_local_date();
+        }
+        case value_t::local_time:
+        {
+            return lhs.as_local_time() == rhs.as_local_time();
+        }
+        case value_t::array    :
+        {
+            return lhs.as_array() == rhs.as_array();
+        }
+        case value_t::table    :
+        {
+            return lhs.as_table() == rhs.as_table();
+        }
+        case value_t::empty    : {return true; }
+        default:                 {return false;}
+    }
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+inline bool operator!=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    return !(lhs == rhs);
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+typename std::enable_if<detail::conjunction<
+    detail::is_comparable<typename basic_value<C, T, A>::array_type>,
+    detail::is_comparable<typename basic_value<C, T, A>::table_type>
+    >::value, bool>::type
+operator<(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    if(lhs.type() != rhs.type()){return (lhs.type() < rhs.type());}
+    switch(lhs.type())
+    {
+        case value_t::boolean  :
+        {
+            return lhs.as_boolean() <  rhs.as_boolean() ||
+                  (lhs.as_boolean() == rhs.as_boolean() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::integer  :
+        {
+            return lhs.as_integer() <  rhs.as_integer() ||
+                  (lhs.as_integer() == rhs.as_integer() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::floating :
+        {
+            return lhs.as_floating() <  rhs.as_floating() ||
+                  (lhs.as_floating() == rhs.as_floating() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::string   :
+        {
+            return lhs.as_string() <  rhs.as_string() ||
+                  (lhs.as_string() == rhs.as_string() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::offset_datetime:
+        {
+            return lhs.as_offset_datetime() <  rhs.as_offset_datetime() ||
+                  (lhs.as_offset_datetime() == rhs.as_offset_datetime() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::local_datetime:
+        {
+            return lhs.as_local_datetime() <  rhs.as_local_datetime() ||
+                  (lhs.as_local_datetime() == rhs.as_local_datetime() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::local_date:
+        {
+            return lhs.as_local_date() <  rhs.as_local_date() ||
+                  (lhs.as_local_date() == rhs.as_local_date() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::local_time:
+        {
+            return lhs.as_local_time() <  rhs.as_local_time() ||
+                  (lhs.as_local_time() == rhs.as_local_time() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::array    :
+        {
+            return lhs.as_array() <  rhs.as_array() ||
+                  (lhs.as_array() == rhs.as_array() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::table    :
+        {
+            return lhs.as_table() <  rhs.as_table() ||
+                  (lhs.as_table() == rhs.as_table() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::empty    :
+        {
+            return lhs.comments() < rhs.comments();
+        }
+        default:
+        {
+            return lhs.comments() < rhs.comments();
+        }
+    }
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+typename std::enable_if<detail::conjunction<
+    detail::is_comparable<typename basic_value<C, T, A>::array_type>,
+    detail::is_comparable<typename basic_value<C, T, A>::table_type>
+    >::value, bool>::type
+operator<=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    return (lhs < rhs) || (lhs == rhs);
+}
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+typename std::enable_if<detail::conjunction<
+    detail::is_comparable<typename basic_value<C, T, A>::array_type>,
+    detail::is_comparable<typename basic_value<C, T, A>::table_type>
+    >::value, bool>::type
+operator>(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    return !(lhs <= rhs);
+}
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+typename std::enable_if<detail::conjunction<
+    detail::is_comparable<typename basic_value<C, T, A>::array_type>,
+    detail::is_comparable<typename basic_value<C, T, A>::table_type>
+    >::value, bool>::type
+operator>=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    return !(lhs < rhs);
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+inline std::string format_error(const std::string& err_msg,
+        const basic_value<C, T, A>& v, const std::string& comment,
+        std::vector<std::string> hints = {},
+        const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
+{
+    return detail::format_underline(err_msg, {{v.location(), comment}},
+                                    std::move(hints), colorize);
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+inline std::string format_error(const std::string& err_msg,
+        const toml::basic_value<C, T, A>& v1, const std::string& comment1,
+        const toml::basic_value<C, T, A>& v2, const std::string& comment2,
+        std::vector<std::string> hints = {},
+        const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
+{
+    return detail::format_underline(err_msg, {
+            {v1.location(), comment1}, {v2.location(), comment2}
+        }, std::move(hints), colorize);
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+inline std::string format_error(const std::string& err_msg,
+        const toml::basic_value<C, T, A>& v1, const std::string& comment1,
+        const toml::basic_value<C, T, A>& v2, const std::string& comment2,
+        const toml::basic_value<C, T, A>& v3, const std::string& comment3,
+        std::vector<std::string> hints = {},
+        const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
+{
+    return detail::format_underline(err_msg, {{v1.location(), comment1},
+            {v2.location(), comment2}, {v3.location(), comment3}
+        }, std::move(hints), colorize);
+}
+
+template<typename Visitor, typename C,
+         template<typename ...> class T, template<typename ...> class A>
+detail::return_type_of_t<Visitor, const toml::boolean&>
+visit(Visitor&& visitor, const toml::basic_value<C, T, A>& v)
+{
+    switch(v.type())
+    {
+        case value_t::boolean        : {return visitor(v.as_boolean        ());}
+        case value_t::integer        : {return visitor(v.as_integer        ());}
+        case value_t::floating       : {return visitor(v.as_floating       ());}
+        case value_t::string         : {return visitor(v.as_string         ());}
+        case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
+        case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
+        case value_t::local_date     : {return visitor(v.as_local_date     ());}
+        case value_t::local_time     : {return visitor(v.as_local_time     ());}
+        case value_t::array          : {return visitor(v.as_array          ());}
+        case value_t::table          : {return visitor(v.as_table          ());}
+        case value_t::empty          : break;
+        default: break;
+    }
+    throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
+            "does not have any valid basic_value.", v, "here"));
+}
+
+template<typename Visitor, typename C,
+         template<typename ...> class T, template<typename ...> class A>
+detail::return_type_of_t<Visitor, toml::boolean&>
+visit(Visitor&& visitor, toml::basic_value<C, T, A>& v)
+{
+    switch(v.type())
+    {
+        case value_t::boolean        : {return visitor(v.as_boolean        ());}
+        case value_t::integer        : {return visitor(v.as_integer        ());}
+        case value_t::floating       : {return visitor(v.as_floating       ());}
+        case value_t::string         : {return visitor(v.as_string         ());}
+        case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
+        case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
+        case value_t::local_date     : {return visitor(v.as_local_date     ());}
+        case value_t::local_time     : {return visitor(v.as_local_time     ());}
+        case value_t::array          : {return visitor(v.as_array          ());}
+        case value_t::table          : {return visitor(v.as_table          ());}
+        case value_t::empty          : break;
+        default: break;
+    }
+    throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
+            "does not have any valid basic_value.", v, "here"));
+}
+
+template<typename Visitor, typename C,
+         template<typename ...> class T, template<typename ...> class A>
+detail::return_type_of_t<Visitor, toml::boolean&&>
+visit(Visitor&& visitor, toml::basic_value<C, T, A>&& v)
+{
+    switch(v.type())
+    {
+        case value_t::boolean        : {return visitor(std::move(v.as_boolean        ()));}
+        case value_t::integer        : {return visitor(std::move(v.as_integer        ()));}
+        case value_t::floating       : {return visitor(std::move(v.as_floating       ()));}
+        case value_t::string         : {return visitor(std::move(v.as_string         ()));}
+        case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));}
+        case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));}
+        case value_t::local_date     : {return visitor(std::move(v.as_local_date     ()));}
+        case value_t::local_time     : {return visitor(std::move(v.as_local_time     ()));}
+        case value_t::array          : {return visitor(std::move(v.as_array          ()));}
+        case value_t::table          : {return visitor(std::move(v.as_table          ()));}
+        case value_t::empty          : break;
+        default: break;
+    }
+    throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
+            "does not have any valid basic_value.", v, "here"));
+}
+
+}// toml
+#endif// TOML11_VALUE