4

I'm trying to write outside class template operator for template class inside template class.

I hope the following snippet will explain what I mean.

enum MyEnum {};

template <MyEnum a>
class ClassWithTemplateClass {
 public:
    template <bool B> 
    class TemplateClass {
        // ...
    };
};

When I wrote operator like this:

template <MyEnum enumVal, bool B>
auto operator<<(ClassWithTemplateClass<enumVal>::TemplateClass<B> &a, int b) {
    // ...
    return a;
}

compiler returned error:

error: declaration of 'operator<<' as non-function

Can you tell me how I should write this operator?

pokas
  • 41
  • 2
  • Try a search with your error message: http://stackoverflow.com/search?q=error%3A+declaration+of+%27operator%3C%3C%27+as+non-function. There are quite a few questions (and answers). – Olaf Dietsche Dec 20 '15 at 13:39
  • 1
    You really can't write this one outside the class template definitions. Sprinkling `typename` and `template` will make it compile, but the whole thing is a non-deduced context so your operator will never be called unless you do it explicitly - which defeats the whole point of overloading operators. – T.C. Dec 20 '15 at 13:50

1 Answers1

1

ClassWithTemplateClass<enumVal>:: is a nested name specifier which in turn is a non-deduced context. Since enumVal is a template parameter that appears to the left of a scope resolution operator ::, its value cannot be deduced by the compiler.

The << operator can be defined (1) as a friend inside class TemplateClass:

enum MyEnum { X, Y, Z };

template <MyEnum E>
struct ClassWithTemplateClass
{
    template <bool B> 
    struct TemplateClass
    {
        friend auto& operator<<(TemplateClass& a, int b)
        {
            return a;
        }
    };
};

where TemplateClass always refers to a particular instantiation of ClassWithTemplateClass<?>::TemplateClass<?>

DEMO

or (2) inside ClassWithTemplateClass:

enum MyEnum { X, Y, Z };

template <MyEnum E>
struct ClassWithTemplateClass
{
    template <bool B> 
    struct TemplateClass
    {
    };

    template <bool B>
    friend auto& operator<<(TemplateClass<B>& a, int b)
    {
        return a;
    }
};

DEMO 2

or, (3) you could provide a separate operator definition for each pre-defined enum value (though it can have more values than defined as constants), so that only B needs to be deduced:

enum MyEnum { X, Y, Z };

template <MyEnum E>
struct ClassWithTemplateClass
{
    template <bool B> 
    struct TemplateClass
    {        
    };
};

template <bool B>
auto& operator<<(ClassWithTemplateClass<X>::TemplateClass<B>& a, int b)
{
    return a;
}

template <bool B>
auto& operator<<(ClassWithTemplateClass<Y>::TemplateClass<B>& a, int b)
{
    return a;
}

template <bool B>
auto& operator<<(ClassWithTemplateClass<Z>::TemplateClass<B>& a, int b)
{
    return a;
}

DEMO 3

, or (4) store template parameters as static data members of TemplateClass, and use them to both make the operator SFINAE-able and to retrieve their values:

enum MyEnum { X, Y, Z };

template <MyEnum E>
struct ClassWithTemplateClass
{
    template <bool B> 
    struct TemplateClass
    {
        static constexpr MyEnum ClassWithTemplateClass_E = E;
        static constexpr bool TemplateClass_B = B;
    };
};

template <typename T
        , MyEnum E = T::ClassWithTemplateClass_E
        , bool B = T::TemplateClass_B>
auto& operator<<(T& a, int b)
{
    return a;
}

DEMO 4

As another alternative, (5) you can dispatch the call from operator<< to another function, and explicitly specify its template arguments, so that the signature is exactly as you wanted, and the template parameters are known:

enum MyEnum { X, Y, Z };

template <MyEnum E>
struct ClassWithTemplateClass;

template <MyEnum E, bool B>
auto& print(typename ClassWithTemplateClass<E>::template TemplateClass<B>& a, int b);

template <MyEnum E>
struct ClassWithTemplateClass
{
    template <bool B> 
    struct TemplateClass
    {
        friend auto& operator<<(TemplateClass& a, int b)
        {
            return print<E, B>(a, b);
        }
    };
};

template <MyEnum E, bool B>
auto& print(typename ClassWithTemplateClass<E>::template TemplateClass<B>& a, int b)
{
    return a;
}

DEMO 5

Community
  • 1
  • 1
Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • Thank you for answer. Because operators<< will be defined by end user of my library only possible solution is your last demo. But this solution might be too confusing for users of my library, so I think, I need to redesign this part of library. – pokas Dec 20 '15 at 16:05
  • @pokas how about [this solution](http://coliru.stacked-crooked.com/a/4902a6156f460378), where an end-user is supposed to provide function `print_template_class` ? – Piotr Skotnicki Dec 20 '15 at 16:11