Defining an Inner class member function template with a (non type) enum argument
Asked Answered
J

1

6

I'm having difficulty defining and specializing a member function update() of an inner class Outer<T1>::Inner that is templated on a non-type (enum) argument.

#include <cstdlib>

template<typename T1>
struct Outer
{
    struct Inner
    {
        enum Type{ A , B , C };

        template<Type T2>
        void update();
    };
};

// Definition
template<typename T1>
template<Outer<T1>::Inner::Type T2>
void Outer<T1>::Inner::update()
{
}

// Specialization
template<typename T1>
template<Outer<T1>::Inner::A >
void Outer<T1>::Inner::update()
{
}

int main()
{
    return EXIT_SUCCESS;
}

I'm getting the following error message in GCC 4.5.3

prog.cpp:17:28: error: ‘Outer::Inner::Type’ is not a type
prog.cpp:18:6: error: prototype for ‘void Outer<T1>::Inner::update()’ does not match any in class ‘Outer<T1>::Inner’
prog.cpp:11:15: error: candidate is: template<class T1> template<Outer<T1>::Inner::Type T2> void Outer<T1>::Inner::update()
prog.cpp:24:28: error: ‘Outer::Inner::A’ is not a type
prog.cpp:25:6: error: prototype for ‘void Outer<T1>::Inner::update()’ does not match any in class ‘Outer<T1>::Inner’
prog.cpp:11:15: error: candidate is: template<class T1> template<Outer<T1>::Inner::Type T2> void Outer<T1>::Inner::update()

BTW, unlike GCC, Visual Studio 2008 is unable to compile the following

template<typename T1>
struct Outer
{
    struct Inner
    {
        enum Type{ A , B , C };

        template<Type T2>
        struct Deep;
    };
};

template<typename T1>
template<typename Outer<T1>::Inner::Type T2>
struct Outer<T1>::Inner::Deep
{
};
Jaynejaynell answered 8/2, 2013 at 16:9 Comment(4)
I have to admit this genereated one of the more humorous error messages from VC2012 I've seen in awhile: error C2244: 'Outer<T1>::Inner::update' : unable to match function definition to an existing declaration, definition 'void Outer<T1>::Inner::update(void)', existing declarations :'void Outer<T1>::Inner::update(void)' The striking difference between the existing and desired declarations is so obvious, isn't it =PEstren
I was about to remark that Visual Studio 2008 does not approve. Is there a workaround? I'm actually coding in VS. I use GCC for sanity compliance checks.Jaynejaynell
@Jaynejaynell will a runtime check suffice for what you're doing? The compiler will most likely optimise the check and dead code away since it knows it will always be true or false.Socialist
@SethCarnegie it would. However there'll be more than a few if-statements and I was looking to cut down on the number. Fortunately VS is able to compile struct Deep<T2> if the enum is not in class scope.Jaynejaynell
S
5

First of all, you're missing a typename before Outer<T1>::Inner::Type. You have to have it, even in a template type list, because Type is a dependent type.

Secondly, your specialisation syntax is wrong (the type goes in <> after the function name before the parentheses, not in the template<>), but even if it was correct, it would not be legal. You have to specialise the outer template Outer before you can fully specialise update, according to an unfortunate rule regarding explicit template specialisation.

Socialist answered 8/2, 2013 at 16:18 Comment(5)
For the benefit of the unenlightened: What would "specializing the outer template" look like in this case?Arnettearney
@Arnettearney it would just be template<> template<> void Outer<int>::Inner::update<Outer<int>::Inner::A>() or whatever. The point is that Outer has to be specialised as well.Socialist
@Seth Interesting. So there is no way to actually get the functionality that the OP intended, short of specializing for every possible type that might be used as a template parameter to Outer?Arnettearney
@Arnettearney unfortunately yes, that is correct. I was surprised too, but §14.7.3/16 says In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. I think they just wanted to reduce a level of complexity for compiler writers.Socialist
FYI Clang is at fairly clear on their error message for this if you try to do it without specializing Outer<> : "Cannot specialize (with 'template<>') a member of an unspecialized template", which is a helluva lot more informative than Herb's messaging from VC++ (see comment in question).Estren

© 2022 - 2024 — McMap. All rights reserved.