繁体   English   中英

如何在模板类的嵌套类中提供友元运算符的定义?

[英]How to provide the definition of a friend operator in a nested class of a template class?

这有效:

template<class Tim>
struct Bob
{
    struct Dave
    {
        Tim t{};
        friend bool operator < (const Dave& a, const Dave& b)
        {
            return a.t < b.t;
        }
    } d;
};

这不起作用:

template<class Tim>
struct Bob
{
    struct Dave
    {
        Tim t{};
        friend bool operator < (const Dave& a, const Dave& b);
    } d;
};

template<class Tim>
bool operator < (const typename Bob<Tim>::Dave& a, const typename Bob<Tim>::Dave& b)
{
    return a.t < b.t;
}

例如,当我尝试在地图中使用它时,我会收到链接器错误:

1>ConsoleApplication1.obj : error LNK2019: unresolved external symbol "bool __cdecl operator<(struct Bob<int>::Dave const &,struct Bob<int>::Dave const &)" (??M@YA_NABUDave@?$Bob@H@@0@Z) referenced in function "public: bool __thiscall std::less<struct Bob<int>::Dave>::operator()(struct Bob<int>::Dave const &,struct Bob<int>::Dave const &)const " (??R?$less@UDave@?$Bob@H@@@std@@QBE_NABUDave@?$Bob@H@@0@Z)

int main()
{
    std::map<Bob<int>::Dave, int> v;
    v[{}];
}

我怎样才能正确地定义这个操作符类

你通常会通过向前声明模板类和友元函数然后在类定义中提供特化来做这样的事情。 但是,在这种情况下,它并不那么容易 - 具有依赖类型将Tim类放在非推导的上下文中,因此推导将失败。 但是,有一种解决方法:

#include <iostream>
#include <type_traits>
#include <map>

template<class T>
struct Bob;

template<typename T, typename>
bool operator < (const T& a, const T& b);

struct DaveTag {};

template<class Tim>
struct Bob
{
    struct Dave : DaveTag
    {
        Tim t{};


        friend bool operator < <Bob<Tim>::Dave, void>(const typename Bob<Tim>::Dave& a, const typename Bob<Tim>::Dave& b);
    } d;
};

template<typename T, typename = typename std::enable_if<std::is_base_of<DaveTag, T>::value>::type>
bool operator < (const T& a, const T& b)
{
    return a.t < b.t;
}

struct X {
    double t;
};

int main()
{
    std::map<Bob<int>::Dave, int> v;
    v[{}];

    // This won't work
    // X x, y;
    //bool b = x < y;

}

基本上,我在这里做的是让编译器推导出完整的Bob<Tim>::Dave作为operator<的模板参数。 然而,显然一个简单的定义将允许推断出任何类型的T可能导致一些难以理解的问题。 为了避免这种情况,我添加了一个小标签类DaveTag ,它允许阻止我们非常通用的operator<除了Dave任何东西的实例化。

这是一个令人满意的解决方法。 我不想出于各种原因在类中实现运算符(此时定义不可用,此处有一些显式模板实例化)但我可以使用以下内容:

struct Bob
{
    struct Dave
    {
        Tim t{};

        static bool LessThan(const Dave& a, const Dave& b);

        friend bool operator < (const Dave& a, const Dave& b)
        {
            return LessThan(a, b);
        }
    } d;
};

现在,静态函数LessThan可以以正常方式在类外实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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