get.hpp

# get.hpp #

These are functions for extracting values from `toml::value` and performing type conversions if necessary.

> `toml::value` can change the type it stores, and `toml::get` accommodates these types. Technically, all functions use `toml::basic_value<TC>`. However, for simplicity, we refer to it as `toml::value` in explanations unless a distinction is necessary. In the documentation, if the template parameter `TC` changes the type, assume that types like `toml::value::integer_type` will also change accordingly.

# `toml::get<T>` #

## Overview #

Generally, `toml::get` behaves as follows: You specify `T` as in `toml::get<int>(v)`.

    template<typename T, typename TC>
    T get(const basic_value<TC>& v);

However, depending on the type of `T`, `toml::get` can exhibit different behaviors.

The types of `T` can be categorized into:

1. Types that do not require conversion
2. Types that require conversion

Detailed conditions and the specific types supported are discussed later.

### Types that Do Not Require Conversion #

No conversion is needed if the provided `toml::value` is already storing the desired type. For instance, since `toml::value::integer_type` is an alias for `std::int64_t`, `toml::get<std::int64_t>(v)` requires no conversion. In this case, `toml::get` retrieves the `integer` value from `toml::value` and returns a reference to it.

If the provided `toml::value` is a mutable reference (`&`), the returned value is also a mutable reference (`&`). If it is an immutable reference (`const&`), the returned value will also be an immutable reference (`const&`). Returning a mutable reference allows you to overwrite the value stored in `toml::value` through that reference.

### Types that Require Conversion #

Types other than the ones mentioned above require conversion. For example, since `toml::value::integer_type` is an alias for `std::int64_t`, `toml::get<std::size_t>(toml::value&)` requires conversion. In this case, `toml::get` retrieves the `integer` value from `toml::value` and casts it to return the appropriate type.

toml11 supports not only simple casts but also complex type conversions like converting from `toml::array` to `std::tuple<int, double, std::string>`, `std::array<double, 4>`, or from `toml::table` to `std::map<std::string, int>`. For specifics, refer to the subsequent sections.

### When Conversion Fails #

Sometimes, the expected type conversion cannot be performed. For example, applying `toml::get<int>(v)` to a `toml::value` that holds a `table`.

In such cases, an attempt to convert to the type most similar to the desired type (in this case, `int` using `as_integer`) fails, and a `toml::type_error` is thrown.

When parsing from a file, an error message similar to the following is output:

    terminate called after throwing an instance of 'toml::type_error'
      what():  toml::value::as_integer(): bad_cast to integer
     --> input.toml
       |
     6 | [fruit]
       | ^^^^^^^-- the actual type is table

## When `T` is identical to `toml::value` #

    template<typename T, typename TC>
    T& get(basic_value<TC>& v);

    template<typename T, typename TC>
    T const& get(const basic_value<TC>& v);

    template<typename T, typename TC>
    T get(basic_value<TC>&& v);

Condition:

- `std::is_same<T, basic_value<TC>>` is satisfied.

Since this involves retrieving `toml::value` from `toml::value`, no conversion is performed, and the value is returned as is. This exists solely to generalize the implementation of other functions.

This does not fail.

## When `T` is one of `toml::value::{some_type}` #

    template<typename T, typename TC>
    T& get(basic_value<TC>& v);

    template<typename T, typename TC>
    T const& get(const basic_value<TC>& v);

    template<typename T, typename TC>
    T get(basic_value<TC>&& v);

Condition:

- `T` must be the same as one of the types that `toml::value` can store (e.g., `toml::value::boolean_type`).

If `toml::value` is storing a type that matches the specified type in `toml::get<T>`, such as `toml::value::integer_type`, no type conversion is needed, and a reference can be returned.

If a different type is stored, a `toml::type_error` is thrown.

## When `T` is `basic_value<OtherTC>` with a different `TypeConfig` #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition:

- `T` is not `toml::basic_value<TC>`.
- `T` is `toml::basic_value<OtherTC>`.

When a `basic_value` that can store different types is specified, conversion is performed.

Since type conversion occurs, the returned value is a new value and not a reference.

This does not fail (except in cases like memory exhaustion).

## When `T` is an integer type #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition:

- `std::is_integral<T>` is satisfied
- `T` is not `bool`
- `T` is not `toml::value::integer_type`

The function assumes that `toml::value` holds an `integer_type`, retrieves its value, converts it to `T`, and returns it.

If a type other than `toml::value::integer_type` is stored, a `toml::type_error` is thrown.

## When `T` is a floating-point type #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition:

- `std::is_floating_point<T>` is satisfied
- `T` is not `toml::value::floating_type`

The function assumes that `toml::value` holds a `floating_type`, retrieves its value, converts it to `T`, and returns it.

If a type other than `toml::value::floating_type` is stored, a `toml::type_error` is thrown.

## When `T` is `std::string_view` #

This is only available in C++17 and later.

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition:

- `std::is_same<std::string_view, T>` is satisfied

The function assumes that `toml::value` holds a `string_type`, retrieves its value, constructs a `std::string_view` from it, and returns it.

If a type other than `toml::value::string_type` is stored, a `toml::type_error` is thrown.

## When `T` is `std::chrono::duration` #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition:

- `T` is `std::chrono::duration<Rep, Period>`

The function assumes that `toml::value` holds a `local_time`, retrieves its value, converts it to `std::chrono::duration`, and returns it.

If a type other than `toml::value::local_time` is stored, a `toml::type_error` is thrown.

## When `T` is `std::chrono::system_clock::time_point` #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition:

- `std::is_same<T, std::chrono::system_clock::time_point>` is satisfied

If the `toml::value` holds a `local_date`, `local_datetime`, or `offset_datetime`, this function retrieves the value and converts it to `std::chrono::system_clock::time_point`, returning the result.

If the value is of a type other than `local_date`, `local_datetime`, or `offset_datetime`, a `toml::type_error` is thrown.

## When `T` is array-like #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Conditions:

- `T` has an `iterator`
- `T` has a `value_type`
- `T` supports `push_back(x)`
- `T` is not `toml::value::array_type`
- `T` is not `std::string`
- `T` is not `std::string_view`
- `T` is not map-like
- `T` does not have `from_toml()` member function
- `toml::from<T>` is not defined
- A constructor from `toml::basic_value<TC>` is not defined

This includes types like `std::vector<int>` and `std::deque<std::string>`.

If the `toml::value` holds an `array`, this function retrieves the value and converts it to the specified container type, returning the result.

If the value is of a type other than `toml::value::array_type`, a `toml::type_error` is thrown.

## When `T` is `std::array` #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition：

- `T` is `std::array<U, N>`

If the `toml::value` holds an `array`, this function retrieves the value and converts it to the specified container type, returning the result.

If the value is of a type other than `toml::value::array_type`, a `toml::type_error` is thrown.

If the `array` held by `toml::value` does not contain enough elements, a `std::out_of_range` is thrown.

## When `T` is `std::forward_list` #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition:

- `T` is `std::forward_list<U>`

If the `toml::value` holds an `array`, this function retrieves the value and converts it to a `std::forward_list`, returning the result.

If the value is of a type other than `toml::value::array_type`, a `toml::type_error` is thrown.

## When `T` is `std::pair` #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition:

- `T` is `std::pair<T1, T2>`

If the `toml::value` holds an `array`, this function retrieves the value and converts it to `std::pair<T1, T2>`, returning the result.

The `first` and `second` elements are recursively converted.

If the value is of a type other than `basic_value::array_type`, a `toml::type_error` is thrown.

If the `array` held by `toml::value` does not contain exactly 2 elements, a `std::out_of_range` is thrown.

## When `T` is `std::tuple` #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition:

- `T` is `std::tuple<T1, T2, ... TN>`

If the `toml::value` holds an `array`, this function retrieves the value and converts it to `std::tuple<T1, T2, ...TN>`, returning the result.

Each element is recursively converted.

If the value is of a type other than `basic_value::array_type`, a `toml::type_error` is thrown.

If the `array` held by `toml::value` does not contain exactly `std::tuple_size<T>::value` elements, a `std::out_of_range` is thrown.

## When `T` is map-like #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Conditions:

- `T` has an `iterator`
- `T` has a `key_type`
- `T` has a `value_type`
- `T` has a `mapped_type`
- `T` is not `toml::value::table_type`
- `T` does not have a `from_toml()` member function
- `toml::from<T>` is not defined
- A constructor from `toml::basic_value<TC>` is not defined

This includes types like `std::map<std::string, int>` and `std::unordered_map<std::string, float>`.

If the `toml::value` holds a `table`, this function retrieves the value and converts it to `T`, returning the result.

Elements are recursively converted.

If the value is of a type other than `basic_value::table_type`, a `toml::type_error` is thrown.

## When `T` is a user-defined type with a specialization of `toml::from<T>` #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Condition:

- A specialization of `toml::from<T>` is defined

If a specialization of `toml::from` for `T` is defined, it is used for type conversion.

Ensure this does not conflict with individually supported types (`std::array`, `std::pair`, `std::tuple` etc).

## When `T` is a user-defined type with a `from_toml` member function #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Conditions:

- `toml::from<T>` is not defined
- `T` has `from_toml()` member function

If `T` has a `from_toml(toml::basic_value<TC>)` member function, it is used for type conversion.

If `toml::from<T>` is defined, it takes precedence.

## When `T` is a user-defined type with a constructor that takes `toml::basic_value<TC>` #

    template<typename T, typename TC>
    T get(basic_value<TC>& v);

Conditions:

- `toml::from<T>` is not defined
- `T` does not have `from_toml()` member function
- `T` has a constructor that takes `toml::basic_value<TC>`

If `T` has a constructor that takes `toml::basic_value<TC>`, it is used for type conversion.

If `toml::from<T>` or `T::from_toml` is defined, they take precedence.

# `toml::get_or<T>` #

`get_or` takes a default value for use when the conversion fails, avoiding exceptions.

The default value must be of the same type as the target type `T`. Therefore, unlike `toml::get<T>`, `T` can be inferred in `get_or`.

## When `T` is `basic_value<TC>` #

    template<typename TC>
    basic_value<TC> const& get_or(const basic_value<TC>& v, const basic_value<TC>& opt)

    template<typename TC>
    basic_value<TC> & get_or(basic_value<TC>& v, basic_value<TC>& opt)

    template<typename TC>
    basic_value<TC> get_or(basic_value<TC>&& v, basic_value<TC>&& opt)

Since the conversion target is the same `toml::value`, this never fails.

It exists solely to generalize the implementation of other functions.

## When `T` is `basic_value<TC>::{some_type}` #

    template<typename T, typename TC>
    T const& get_or(const basic_value<TC>& v, const T& opt) noexcept

    template<typename T, typename TC>
    T & get_or(basic_value<TC>& v, T& opt) noexcept

    template<typename T, typename TC>
    T get_or(basic_value<TC>&& v, T&& opt) noexcept

Performs the same conversion as `toml::get<T>`. If it fails, the second argument is returned.

## When `T` is `const char*` #

    template<typename TC>
    typename basic_value<TC>::string_type
    get_or(const basic_value<TC>& v,
           const typename basic_value<TC>::string_type::value_type* opt);

When `const char*` is passed, the conversion target is interpreted as `std::string`.

## When `T` is something else #

    template<typename TC>
    typename std::remove_cv<typename std::remove_reference<T>::type>::type
    get_or(const basic_value<TC>& v, T&& opt);

Performs the same conversion as `toml::get<T>`. If it fails, the second argument is returned.

# Related #

- find.hpp
- from.hpp
- value.hpp