Boost.Hana: boost::hana::tag_of< T, enabler > Struct Template Reference

| Boost.Hana 1.0.0 Your standard library for metaprogramming |

boost::hana::tag_of< T, enabler > Struct Template Reference
Core

## Description

### template<typename T, optional when-based enabler>
struct boost::hana::tag_of< T, enabler >

Metafunction returning the tag associated to `T`.

There are several ways to specify the tag of a C++ type. If it's a user-defined type, one can define a nested `hana_tag` alias:

struct MyUserDefinedType {
using hana_tag = MyTag;
};

Sometimes, however, the C++ type can't be modified (if it's in a foreign library) or simply can't have nested types (if it's not a struct or class). In those cases, using a nested alias is impossible and so ad-hoc customization is also supported by specializing `tag_of` in the `boost::hana` namespace:

struct i_cant_modify_this;
namespace boost { namespace hana {
template <>
struct tag_of<i_cant_modify_this> {
using type = MyTag;
};
}}

`tag_of` can also be specialized for all C++ types satisfying some boolean condition using `when`. `when` accepts a single compile-time boolean and enables the specialization of `tag_of` if and only if that boolean is `true`. This is similar to the well known C++ idiom of using a dummy template parameter with `std::enable_if` and relying on SFINAE. For example, we could specify the tag of all `fusion::vector`s by doing:

struct BoostFusionVector;
namespace boost { namespace hana {
template <typename T>
struct tag_of<T, when<
std::is_same<
typename fusion::traits::tag_of<T>::type,
fusion::traits::tag_of<fusion::vector<>>::type
>{}
>> {
using type = BoostFusionVector;
};
}}

Also, when it is not specialized and when the given C++ type does not have a nested `hana_tag` alias, `tag_of<T>` returns `T` itself. This makes tags a simple extension of normal C++ types. This is super useful, mainly for two reasons. First, this allows Hana to adopt a reasonable default behavior for some operations involving types that have no notion of tags. For example, Hana allows comparing with `equal` any two objects for which a valid `operator==` is defined, and that without any work on the user side. Second, it also means that you can ignore tags completely if you don't need their functionality; just use the normal C++ type of your objects and everything will "just work".

Finally, also note that `tag_of<T>` is always equivalent to `tag_of<U>`, where `U` is the type `T` after being stripped of all references and cv-qualifiers. This makes it unnecessary to specialize `tag_of` for all reference and cv combinations, which would be a real pain. Also, `tag_of` is required to be idempotent. In other words, it must always be the case that `tag_of<tag_of<T>::type>::type` is equivalent to `tag_of<T>::type`.

> Tip 1
> If compile-time performance is a serious concern, consider specializing the `tag_of` metafunction in Hana's namespace. When unspecialized, the metafunction has to use SFINAE, which tends to incur a larger compile-time overhead. For heavily used templated types, this can potentially make a difference.

> Tip 2
> Consider using `tag_of_t` alias instead of `tag_of`, which reduces the amount of typing in dependent contexts.

## Example

// Copyright Louis Dionne 2013-2016
// 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 <boost/hana/core/tag_of.hpp>
#include <type_traits>
namespace hana = boost::hana;
static_assert(std::is_same<hana::tag_of<int>::type, int>{}, "");
static_assert(std::is_same<hana::tag_of<int&>::type, int>{}, "");
static_assert(std::is_same<hana::tag_of<int const&>::type, int>{}, "");
struct PersonTag;
struct Person { using hana_tag = PersonTag; };
static_assert(std::is_same<hana::tag_of<Person>::type, PersonTag>{}, "");
static_assert(std::is_same<hana::tag_of<Person volatile&&>::type, PersonTag>{}, "");
int main() { }