模板类内部模板类的外部类运算符

outside class operator for template class inside template class

本文关键字:运算符 外部 内部      更新时间:2023-10-16

我正在尝试为模板类内部的模板类编写类外模板运算符。

我希望下面的片段能解释我的意思。

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

当我写这样的操作员:

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

编译器返回错误:

错误:'operator<lt;'作为非功能

你能告诉我该怎么写这个运算符吗?

ClassWithTemplateClass<enumVal>::是一个嵌套的名称说明符,而它又是一个非推导上下文。由于enumVal是出现在作用域解析运算符::左侧的模板参数,因此编译器无法推导其值。

<<运算符可以定义为(1)类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;
        }
    };
};

其中TemplateClass总是指ClassWithTemplateClass<?>::TemplateClass<?> 的特定实例化

演示

或(2)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;
    }
};

演示2

或者,(3)您可以为每个预定义的枚举值提供一个单独的运算符定义(尽管它可以有比定义为常量更多的值),因此只需要推导B

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;
}

演示3

,或(4)将模板参数存储为TemplateClass的静态数据成员,并使用它们使运算符SFINAE能够检索它们的值:

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;
}

演示4

作为另一种选择,(5)您可以将调用从operator<<调度到另一个函数,并显式指定其模板参数,这样签名就完全符合您的要求,并且模板参数是已知的:

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;
}

演示5