Michel
Michel

Reputation: 372

C++ template specializations not working with nested types

The following code compiles, but will not work:

template<typename T>
struct Nesting
{
    template<typename U>
    struct _Nested
    {
    };

    template<typename U>
    using Nested = _Nested<U>;
};

template<typename T>
struct F
{
    static constexpr bool is_my_nested_class = false;
};

template<typename T, typename U>
struct F<typename Nesting<T>::Nested<U>>
{
    static constexpr bool is_my_nested_class = true;
};

I create these Nesting and Nested types and try to uses a type trait pattern on it. It compiles (using MSVC 2014 w/ CPP11), but

F<Nesting<int>::Nested<long>>::is_my_nested_class

returns false.

Is this forbidden or undefined by the standard ? What rule does it break ? Any workaround ?

Thank you very much!

Upvotes: 4

Views: 613

Answers (1)

davmac
davmac

Reputation: 20631

Your nested alias could refer to any type, particularly in a specialisation:

template<typename T>
struct Nesting
{
    template<typename U>
    struct _Nested
    {
    };

    template<typename U>
    using Nested = _Nested<U>;
};

// Consider this specialisation:
template<>
struct Nesting<int>
{
    template<typename U>
    using Nested = float;
};

Now, clearly F<Nesting<int>::Nested<int>>::is_my_nested_class should be the same as F<float>::is_my_nested_class, however, how can the compiler deduce this for the latter case? That is, if I wrote:

static_assert(F<float>::is_my_nested_class, "not nested");

The compiler would need to see that F<float> is the same as F<Nesting<int>::Nested<int>>, even though the latter hasn't been instantiated. As it can't reasonably be expected to do so, the case is disallowed.

Upvotes: 1

Related Questions