Boost.Hana  1.7.1
Your standard library for metaprogramming
Struct

Description

The Struct concept represents struct-like user-defined types.

The Struct concept allows restricted compile-time reflection over user-defined types. In particular, it allows accessing the names of the members of a user-defined type, and also the value of those members. Structs can also be folded, searched and converted to some types of containers, where more advanced transformations can be performed.

While all types can in theory be made Structs, only a subset of them are actually interesting to see as such. More precisely, it is only interesting to make a type a Struct when it is conceptually a C++ struct, i.e. a mostly dumb aggregate of named data. The way this data is accessed is mostly unimportant to the Struct concept; it could be through getters and setters, through public members, through non-member functions or it could even be generated on-the-fly. The important part, which is made precise below, is that those accessor methods should be move-independent.

Another way to see a Struct is as a map where the keys are the names of the members and the values are the values of those members. However, there are subtle differences like the fact that one can't add a member to a Struct, and also that the order of the members inside a Struct plays a role in determining the equality of Structs, which is not the case for maps.

Minimal complete definition

accessors

A model of Struct is created by specifying a sequence of key/value pairs with the accessors function. The first element of a pair in this sequence represents the "name" of a member of the Struct, while the second element is a function which retrieves this member from an object. The "names" do not have to be in any special form; they just have to be compile-time Comparable. For example, it is common to provide "names" that are hana::strings representing the actual names of the members, but one could provide hana::integral_constants just as well. The values must be functions which, when given an object, retrieve the appropriate member from it.

There are several ways of providing the accessors method, some of which are more flexible and others which are more convenient. First, one can define it through tag-dispatching, as usual.

struct Person {
std::string name;
int age;
};
// The keys can be anything as long as they are compile-time comparable.
constexpr auto name = hana::integral_c<std::string Person::*, &Person::name>;
constexpr auto age = hana::string_c<'a', 'g', 'e'>;
namespace boost { namespace hana {
template <>
struct accessors_impl<Person> {
static BOOST_HANA_CONSTEXPR_LAMBDA auto apply() {
return make_tuple(
make_pair(name, [](auto&& p) -> decltype(auto) {
return id(std::forward<decltype(p)>(p).name);
}),
make_pair(age, [](auto&& p) -> decltype(auto) {
return id(std::forward<decltype(p)>(p).age);
})
);
}
};
}}
constexpr auto apply
Invokes a Callable with the given arguments.
Definition: apply.hpp:40
constexpr auto id
The identity function – returns its argument unchanged.
Definition: id.hpp:23

Secondly, it is possible to provide a nested hana_accessors_impl type, which should be equivalent to a specialization of accessors_impl for tag-dispatching. However, for a type S, this technique only works when the data type of S is S itself, which is the case unless you explicitly asked for something else.

struct Person {
std::string name;
int age;
struct hana_accessors_impl {
static BOOST_HANA_CONSTEXPR_LAMBDA auto apply() {
return boost::hana::make_tuple(
boost::hana::make_pair(BOOST_HANA_STRING("name"),
[](auto&& p) -> decltype(auto) {
return boost::hana::id(std::forward<decltype(p)>(p).name);
}),
boost::hana::make_pair(BOOST_HANA_STRING("age"),
[](auto&& p) -> decltype(auto) {
return boost::hana::id(std::forward<decltype(p)>(p).age);
})
);
}
};
};

Finally, the most convenient (but least flexible) option is to use the BOOST_HANA_DEFINE_STRUCT, the BOOST_HANA_ADAPT_STRUCT or the BOOST_HANA_ADAPT_ADT macro, which provide a minimal syntactic overhead. See the documentation of these macros for details on how to use them.

Also note that it is not important that the accessor functions retrieve an actual member of the struct (e.g. x.member). Indeed, an accessor function could call a custom getter or even compute the value of the member on the fly:

struct Person {
Person(std::string const& name, int age) : name_(name), age_(age) { }
std::string const& get_name() const { return name_; }
int get_age() const { return age_; }
private:
std::string name_;
int age_;
};
namespace boost { namespace hana {
template <>
struct accessors_impl<Person> {
static BOOST_HANA_CONSTEXPR_LAMBDA auto apply() {
return make_tuple(
make_pair(BOOST_HANA_STRING("name"), [](auto&& p) -> std::string const& {
return p.get_name();
}),
make_pair(BOOST_HANA_STRING("age"), [](auto&& p) {
return p.get_age();
})
);
}
};
}}

The only important thing is that the accessor functions are move-independent, a notion which is defined below.

Move-independence

The notion of move-independence presented here defines rigorously when it is legitimate to "double-move" from an object.

A collection of functions f1, ..., fn sharing the same domain is said to be move-independent if for every fresh (not moved-from) object x in the domain, any permutation of the following statements is valid and leaves the zk objects in a fresh (not moved-from) state:

auto z1 = f1(std::move(x));
...
auto zn = fn(std::move(x));
Note
In the special case where some functions return objects that can't be bound to with auto zk = (like void or a non-movable, non-copyable type), just pretend the return value is ignored.

Intuitively, this ensures that we can treat f1, ..., fn as "accessors" that decompose x into independent subobjects, and that do so without moving from x more than that subobject. This is important because it allows us to optimally decompose Structs into their subparts inside the library.

Laws

For any Struct S, the accessors in the accessors<S>() sequence must be move-independent, as defined above.

Refined concepts

  1. Comparable (free model)
    Structs are required to be Comparable. Specifically, two Structs of the same data type S must be equal if and only if all of their members are equal. By default, a model of Comparable doing just that is provided for models of Struct. In particular, note that the comparison of the members is made in the same order as they appear in the hana::members sequence.
    // Copyright Louis Dionne 2013-2017
    // Distributed under the Boost Software License, Version 1.0.
    // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
    #include <string>
    namespace hana = boost::hana;
    struct Person {
    (std::string, name),
    (unsigned short, age)
    );
    };
    int main() {
    Person john{"John", 30}, kevin{"Kevin", 20};
    }
    Defines macros to perform different kinds of assertions.
    Defines the BOOST_HANA_DEFINE_STRUCT macro.
    Defines boost::hana::equal.
    constexpr auto equal
    Returns a Logical representing whether x is equal to y.
    Definition: equal.hpp:64
    constexpr auto not_equal
    Returns a Logical representing whether x is not equal to y.
    Definition: not_equal.hpp:54
    auto BOOST_HANA_DEFINE_STRUCT(...)
    Defines members of a structure, while at the same time modeling Struct.
    #define BOOST_HANA_RUNTIME_CHECK(...)
    Equivalent to BOOST_HANA_RUNTIME_ASSERT, but not influenced by the BOOST_HANA_CONFIG_DISABLE_ASSERTIO...
    Definition: assert.hpp:209
    Defines boost::hana::keys.
    Namespace containing everything in the library.
    Definition: accessors.hpp:20
    Defines boost::hana::not_equal.
    Defines boost::hana::string.
  2. Foldable (free model)
    A Struct can be folded by considering it as a list of pairs each containing the name of a member and the value associated to that member, in the same order as they appear in the hana::members sequence. By default, a model of Foldable doing just that is provided for models of the Struct concept.
    // Copyright Louis Dionne 2013-2017
    // Distributed under the Boost Software License, Version 1.0.
    // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
    namespace hana = boost::hana;
    struct Kitten {
    (int, extremely_cute),
    (int, cute),
    (int, not_so_cute)
    );
    };
    int main() {
    constexpr Kitten kitten{5, 10, 0};
    hana::fold_left(kitten, 0, [](auto total, auto member) {
    // first(member) is the name of the member, here
    // "extremely_cute", or "cute" or "not_so_cute",
    // and second(member) is its value.
    return hana::second(member) + total;
    }) == (5 + 10 + 0)
    );
    }
    Defines boost::hana::fold_left.
    constexpr auto second
    Returns the second element of a pair.
    Definition: second.hpp:32
    #define BOOST_HANA_CONSTEXPR_CHECK(...)
    Equivalent to BOOST_HANA_CONSTEXPR_ASSERT, but not influenced by the BOOST_HANA_CONFIG_DISABLE_ASSERT...
    Definition: assert.hpp:300
    Defines boost::hana::second.
    Being a model of Foldable makes it possible to turn a Struct into basically any Sequence, but also into a hana::map by simply using the to<...> function!
    // Copyright Louis Dionne 2013-2017
    // Distributed under the Boost Software License, Version 1.0.
    // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
    #include <string>
    namespace hana = boost::hana;
    struct Person {
    (std::string, name),
    (unsigned short, age)
    );
    };
    int main() {
    Person john{"John", 30u};
    BOOST_HANA_RUNTIME_CHECK(hana::to<hana::map_tag>(john) == hana::make_map(
    hana::make_pair(BOOST_HANA_STRING("name"), "John"),
    hana::make_pair(BOOST_HANA_STRING("age"), 30u)
    ));
    }
    Defines boost::hana::to and related utilities.
    Defines boost::hana::map.
    Defines boost::hana::pair.
  3. Searchable (free model)
    A Struct can be searched by considering it as a map where the keys are the names of the members of the Struct, and the values are the members associated to those names. By default, a model of Searchable is provided for any model of the Struct concept.
    // Copyright Louis Dionne 2013-2017
    // Distributed under the Boost Software License, Version 1.0.
    // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
    #include <string>
    namespace hana = boost::hana;
    struct Person {
    (std::string, name),
    (unsigned short, age)
    );
    };
    int main() {
    Person john{"John", 30};
    hana::find(john, BOOST_HANA_STRING("name")) == hana::just("John")
    );
    hana::find(john, BOOST_HANA_STRING("foobar")) == hana::nothing
    );
    hana::all_of(hana::accessors<Person>(), [&](auto a) {
    return hana::second(a)(john) == hana::second(a)(john);
    })
    );
    // the above is equivalent to:
    }
    Defines boost::hana::accessors.
    Defines boost::hana::all_of.
    Defines boost::hana::find.
    constexpr auto all_of
    Returns whether all the keys of the structure satisfy the predicate.
    Definition: all_of.hpp:38
    constexpr auto find
    Finds the value associated to the given key in a structure.
    Definition: find.hpp:44
    #define BOOST_HANA_CONSTANT_CHECK(...)
    Equivalent to BOOST_HANA_CONSTANT_ASSERT, but not influenced by the BOOST_HANA_CONFIG_DISABLE_ASSERTI...
    Definition: assert.hpp:239
    Defines boost::hana::optional.

Functions

auto boost::hana::BOOST_HANA_ADAPT_ADT (...)
 Defines a model of Struct with the given accessors. More...
 
auto boost::hana::BOOST_HANA_ADAPT_STRUCT (...)
 Defines a model of Struct with the given members. More...
 
auto boost::hana::BOOST_HANA_DEFINE_STRUCT (...)
 Defines members of a structure, while at the same time modeling Struct. More...
 

Variables

template<typename S >
constexpr auto boost::hana::accessors
 Returns a Sequence of pairs representing the accessors of the data structure. More...
 
constexpr keys_t boost::hana::keys {}
 Returns a Sequence containing the name of the members of the data structure. More...
 
constexpr auto boost::hana::members
 Returns a Sequence containing the members of a Struct. More...
 

Function Documentation

◆ BOOST_HANA_ADAPT_ADT()

auto boost::hana::BOOST_HANA_ADAPT_ADT (   ...)

#include <boost/hana/fwd/adapt_adt.hpp>

Defines a model of Struct with the given accessors.

Using this macro at global scope will define a model of the Struct concept for the given type. This can be used to easily adapt existing user-defined types in a ad-hoc manner. Unlike BOOST_HANA_ADAPT_STRUCT, this macro requires specifying the way to retrieve each member by providing a function that does the extraction.

Note
This macro only works if the tag of the user-defined type T is T itself. This is the case unless you specifically asked for something different; see tag_of's documentation.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <string>
namespace hana = boost::hana;
namespace ns {
struct Person {
explicit Person(std::string const& name, int age)
: name_(name), age_(age)
{ }
std::string const& get_name() const { return name_; }
int get_age() const { return age_; }
private:
std::string name_;
int age_;
};
}
(name, [](ns::Person const& p) { return p.get_name(); }),
(age, [](ns::Person const& p) { return p.get_age(); })
);
// The member names are hana::strings:
auto names = hana::transform(hana::accessors<ns::Person>(), hana::first);
names == hana::make_tuple(BOOST_HANA_STRING("name"), BOOST_HANA_STRING("age"))
);
int main() {
ns::Person john{"John", 30}, bob{"Bob", 40};
BOOST_HANA_RUNTIME_CHECK(hana::find(john, BOOST_HANA_STRING("name")) == hana::just("John"));
BOOST_HANA_RUNTIME_CHECK(hana::find(john, BOOST_HANA_STRING("age")) == hana::just(30));
BOOST_HANA_CONSTANT_CHECK(hana::find(john, BOOST_HANA_STRING("foo")) == hana::nothing);
BOOST_HANA_RUNTIME_CHECK(hana::to_tuple(john) == hana::make_tuple(
hana::make_pair(BOOST_HANA_STRING("name"), "John"),
hana::make_pair(BOOST_HANA_STRING("age"), 30)
));
BOOST_HANA_RUNTIME_CHECK(hana::to_map(john) == hana::make_map(
hana::make_pair(BOOST_HANA_STRING("name"), "John"),
hana::make_pair(BOOST_HANA_STRING("age"), 30)
));
}
Defines the BOOST_HANA_ADAPT_ADT macro.
Defines boost::hana::first.
constexpr auto first
Returns the first element of a pair.
Definition: first.hpp:33
auto BOOST_HANA_ADAPT_ADT(...)
Defines a model of Struct with the given accessors.
Defines boost::hana::transform.
Defines boost::hana::tuple.

◆ BOOST_HANA_ADAPT_STRUCT()

auto boost::hana::BOOST_HANA_ADAPT_STRUCT (   ...)

#include <boost/hana/fwd/adapt_struct.hpp>

Defines a model of Struct with the given members.

Using this macro at global scope will define a model of the Struct concept for the given type. This can be used to easily adapt existing user-defined types in a ad-hoc manner. Unlike the BOOST_HANA_DEFINE_STRUCT macro, this macro does not require the types of the members to be specified.

Note
This macro only works if the tag of the user-defined type T is T itself. This is the case unless you specifically asked for something different; see tag_of's documentation.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <string>
namespace hana = boost::hana;
namespace ns {
struct Person {
std::string name;
int age;
};
}
name,
age
);
// The member names are hana::strings:
auto names = hana::transform(hana::accessors<ns::Person>(), hana::first);
names == hana::make_tuple(BOOST_HANA_STRING("name"), BOOST_HANA_STRING("age"))
);
int main() {
ns::Person john{"John", 30}, bob{"Bob", 40};
BOOST_HANA_RUNTIME_CHECK(hana::find(john, BOOST_HANA_STRING("name")) == hana::just("John"));
BOOST_HANA_RUNTIME_CHECK(hana::find(john, BOOST_HANA_STRING("age")) == hana::just(30));
BOOST_HANA_CONSTANT_CHECK(hana::find(john, BOOST_HANA_STRING("foo")) == hana::nothing);
BOOST_HANA_RUNTIME_CHECK(hana::to_tuple(john) == hana::make_tuple(
hana::make_pair(BOOST_HANA_STRING("name"), "John"),
hana::make_pair(BOOST_HANA_STRING("age"), 30)
));
BOOST_HANA_RUNTIME_CHECK(hana::to_map(john) == hana::make_map(
hana::make_pair(BOOST_HANA_STRING("name"), "John"),
hana::make_pair(BOOST_HANA_STRING("age"), 30)
));
}
Defines the BOOST_HANA_ADAPT_STRUCT macro.
auto BOOST_HANA_ADAPT_STRUCT(...)
Defines a model of Struct with the given members.

◆ BOOST_HANA_DEFINE_STRUCT()

auto boost::hana::BOOST_HANA_DEFINE_STRUCT (   ...)

#include <boost/hana/fwd/define_struct.hpp>

Defines members of a structure, while at the same time modeling Struct.

Using this macro in the body of a user-defined type will define the given members inside that type, and will also provide a model of the Struct concept for that user-defined type. This macro is often the easiest way to define a model of the Struct concept.

Note
This macro only works if the tag of the user-defined type T is T itself. This is the case unless you specifically asked for something different; see tag_of's documentation.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <string>
namespace hana = boost::hana;
struct Person {
(std::string, name),
(int, age)
);
};
// The member names are hana::strings:
auto names = hana::transform(hana::accessors<Person>(), hana::first);
names == hana::make_tuple(BOOST_HANA_STRING("name"), BOOST_HANA_STRING("age"))
);
int main() {
Person john{"John", 30}, bob{"Bob", 40};
BOOST_HANA_RUNTIME_CHECK(hana::find(john, BOOST_HANA_STRING("name")) == hana::just("John"));
BOOST_HANA_RUNTIME_CHECK(hana::find(john, BOOST_HANA_STRING("age")) == hana::just(30));
BOOST_HANA_CONSTANT_CHECK(hana::find(john, BOOST_HANA_STRING("foo")) == hana::nothing);
BOOST_HANA_RUNTIME_CHECK(hana::to_tuple(john) == hana::make_tuple(
hana::make_pair(BOOST_HANA_STRING("name"), "John"),
hana::make_pair(BOOST_HANA_STRING("age"), 30)
));
BOOST_HANA_RUNTIME_CHECK(hana::to_map(john) == hana::make_map(
hana::make_pair(BOOST_HANA_STRING("name"), "John"),
hana::make_pair(BOOST_HANA_STRING("age"), 30)
));
}

Variable Documentation

◆ accessors

template<typename S >
constexpr auto boost::hana::accessors
constexpr

#include <boost/hana/fwd/accessors.hpp>

Initial value:
= []() {
return tag-dispatched;
}

Returns a Sequence of pairs representing the accessors of the data structure.

Given a Struct S, accessors<S>() is a Sequence of Products where the first element of each pair is the "name" of a member of the Struct, and the second element of each pair is a function that can be used to access that member when given an object of the proper data type. As described in the global documentation for Struct, the accessor functions in this sequence must be move-independent.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <string>
namespace hana = boost::hana;
struct Person {
(std::string, name),
(unsigned short, age)
);
};
int main() {
constexpr auto accessors = hana::accessors<Person>();
hana::first(accessors[hana::size_c<0>]) == BOOST_HANA_STRING("name")
);
hana::first(accessors[hana::size_c<1>]) == BOOST_HANA_STRING("age")
);
constexpr auto get_name = hana::second(accessors[hana::size_c<0>]);
constexpr auto get_age = hana::second(accessors[hana::size_c<1>]);
Person john{"John", 30};
BOOST_HANA_RUNTIME_CHECK(get_name(john) == "John");
BOOST_HANA_RUNTIME_CHECK(get_age(john) == 30);
}
Defines boost::hana::at and boost::hana::at_c.
constexpr auto accessors
Returns a Sequence of pairs representing the accessors of the data structure.
Definition: accessors.hpp:35
Defines boost::hana::integral_constant.

◆ keys

constexpr auto boost::hana::keys {}
related

#include <boost/hana/fwd/keys.hpp>

Returns a Sequence containing the name of the members of the data structure.

Given a Struct object, keys returns a Sequence containing the name of all the members of the Struct, in the same order as they appear in the accessors sequence.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <string>
namespace hana = boost::hana;
struct Person {
(std::string, name),
(unsigned short, age)
);
};
int main() {
Person john{"John", 30};
hana::keys(john) == hana::make_tuple(BOOST_HANA_STRING("name"),
BOOST_HANA_STRING("age"))
);
}
constexpr keys_t keys
Returns a Sequence containing the name of the members of the data structure.
Definition: keys.hpp:29

◆ members

constexpr auto boost::hana::members
constexpr

#include <boost/hana/fwd/members.hpp>

Initial value:
= [](auto&& object) {
return tag-dispatched;
}

Returns a Sequence containing the members of a Struct.

Given a Struct object, members returns a Sequence containing all the members of the Struct, in the same order as their respective accessor appears in the accessors sequence.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <string>
namespace hana = boost::hana;
struct Person {
(std::string, name),
(unsigned short, age)
);
};
int main() {
Person john{"John", 30};
BOOST_HANA_RUNTIME_CHECK(hana::members(john) == hana::make_tuple("John", 30));
}
constexpr auto members
Returns a Sequence containing the members of a Struct.
Definition: members.hpp:30
Defines boost::hana::members.