Boost.Hana  1.5.0
Your standard library for metaprogramming
boost::hana::tag_of< T, enabler > Struct Template Reference

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::vectors 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-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 <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() { }