简体   繁体   中英

How to use the current class template as template parameter for another template?

I'm using recursive templates classes that inherit recursively.
I'm trying to define an abstract way of getting the n-th base (like base 0 is the current class, base 1 is its base, base 2 is the base's base etc.).

(In this example the template parameters are size_t but the same principle applies with typename or class .)

I can do this fine using a helper struct, partially specialized. But I want to make it independent of the template (and not make a helper struct whenever I have a recursive template), as follows:

namespace helper
{
    template<template<size_t...> typename templ, size_t pos, size_t s0, size_t... rest>
    struct getter
    {
        typedef typename getter<templ, pos - 1, rest...>::type type;
        type &operator()(templ<s0, rest...> &s)
        {
            getter<templ, pos - 1, rest...> getter;
            return getter(static_cast<templ<rest...>&> (s));
        }
    };
    template<template<size_t...> typename templ, size_t s0, size_t... rest>
    struct getter<templ, 0, s0, rest...>
    {
        typedef templ<s0, rest...> type;
        type &operator()(templ<s0, rest...> &s)
        {
            return s;
        }
    };
}

Now, in my template class, I want to use this helper to make a function get<size_t n>() that returns me a reference to the n-th base (code fails to compile at get declaration):

template<size_t...>
struct record {};

template<size_t n, size_t... rest>
struct record<n, rest...> : record<rest...>, value<n>
{
    template<size_t pos>
    typename helper::getter<record, pos, n, rest...>::type::value_type &get()
    {
        helper::getter<record, pos, n, rest...> getter;
        return static_cast<typename helper::getter<record, pos, n, rest...>::type::value_type&>(getter(*this));
    }
};

This fails because, inside the record template, record is the final class and not the template. I would like to use something like "current template" instead of "currently instantiated class".

The only workaround I've found (which works under Visual Studio 2015) is to use a global alias to replicate the template:

template<size_t...s>
using g_record = record<s...>;

and then modify the get declaration to call the global alias (which points to the same type):

...
template<size_t pos>
typename helper::getter<g_record, pos, n, rest...>::type::value_type &get()
{
    helper::getter<g_record, pos, n, rest...> getter;
    return static_cast<typename helper::getter<g_record, pos, n, rest...>::type::value_type&>(getter(*this));
}
...

Is there a more direct or a "correct" way to do this?

Looks like I was a bit hasty in my digging.

Apparently using the template's fully qualified name works (in my example it's ::record ):

    template<size_t pos>
    typename helper::getter<::record, pos, n, rest...>::type::value_type &get()
    {
        helper::getter<::record, pos, n, rest...> getter;
        return static_cast<typename helper::getter<::record, pos, n, rest...>::type::value_type&>(getter(*this));
    }

It should not be necessary to use any tricks to get the compiler to realize you are using record as a template name instead of a type name referring to the current instantiation. See [temp.local]/1, emphasis mine:

Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name . When it is used with a template-argument-list , as a template-argument for a template template-parameter , or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself . Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <> .

The workaround you posted is correct, but it should not be needed; this is a bug in the compiler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM