Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Q: Template class that takes either a normal type or a template template argument

Recently I designed meta-types and the possible operations that would allow compile-time type concatenations:

#include <tuple>

template<template<typename...> typename T>
struct MetaTypeTag
{};

/*variable template helper*/
template<template<typename...> typename T>
constexpr MetaTypeTag<T> meta_type_tag = {};

template<typename T>
struct TypeTag
{};

/*comparison*/
template<typename T>
constexpr bool operator==(TypeTag<T>, TypeTag<T>) { return true; }
template<typename T, typename U>
constexpr bool operator==(TypeTag<T>, TypeTag<U>) { return false; }

/*variable template helper*/
template<typename T>
constexpr TypeTag<T> type_tag = {};

template<template<typename...> typename T, typename... Ts>
constexpr TypeTag<T<Ts...>> combine(MetaTypeTag<T>, TypeTag<Ts>...)
{
    return {};
}

int main()
{
    constexpr auto combined_tag = combine(meta_type_tag<std::tuple>, type_tag<int>, type_tag<float>);
    static_assert(combined_tag == type_tag<std::tuple<int, float>>, "");
}

The std::tuple without template arguments cannot be used as a type, but may still appear in the template template parameter.

Now if we try to go one step further, the question is whether there is any way to unify struct MetaTypeTag and struct TypeTag, since they are both empty classes with one template parameter, or at least it could be possible to use the same variable template type_tag but redirect to a different class depending on the type category? So I would imagine something like this:

template<???>
constexpr auto type_tag = ????{};

//use with 'incomplete type'
type_tag<std::tuple> //MetaTypeTag<std::tuple>
//use with regular type
type_tag<int> //TypeTag<int>

I tried all possible ways - redefinition, explicit specialization, partial specialization, optional template parameters, conditional using alias, but none worked. I had hoped C++17's template<auto> would help, but it turns out that one is for non-type only.

like image 644
TheWisp Avatar asked Aug 21 '17 16:08

TheWisp


1 Answers

the question is whether there is any way to unify struct MetaTypeTag and struct TypeTag, since they are both empty classes with one template parameter

I don't thinks so. The best I can imagine to simplify a little (very a little) your code is define a couple of overloaded constexpr function, say getTag()

template <typename T>
auto constexpr getTag ()
 { return TypeTag<T>{}; }

template <template <typename ...> typename T>
auto constexpr getTag ()
 { return MetaTypeTag<T>{}; }

so you can call getTag<T>() where T is either a type or a template.

So you can call combine() as follows

constexpr auto combined_tag
   = combine(getTag<std::tuple>(), getTag<int>(), getTag<float>());

But I don't think is a great improvement.

like image 82
max66 Avatar answered Nov 15 '22 11:11

max66