c++ 声明运算符==用于嵌套模板类

rsaldnfx  于 2023-06-25  发布在  其他
关注(0)|答案(3)|浏览(103)

我在另一个模板类中有一个嵌套的模板类:

template<typename T>
struct A
{
    template<typename V>
    struct B {};
};

嵌套类型B的非成员operator==的签名是什么?下面的简单尝试是行不通的:

template<typename T, typename V>
bool operator==(A<T>::B<V> left, A<T>::B<V> right);

Clang,GCC和MSVC给出了各种不同的错误和/或提示什么是错误的,例如缺少template关键字,但我没有尝试解决它的工作。
请注意,这显然是有效的:

template<typename T>
struct A
{
    template<typename V>
    struct B {};

    template<typename V>
    friend bool operator==(B<V> left, B<V> right)
    {
        return true;
    }
};

**然而,我需要离线非成员声明的原因是使用qdoc记录它。qdoc使用clang来解析源代码,它要求我提供operator==的声明,我实际上已经实现了,就像刚才所示的那样。

LIVE DEMO

mnowg1ta

mnowg1ta1#

这个错误并不遥远,因为您需要template关键字,而且还需要typename来表示依赖类型。工作示例的形式如下:

template <typename T, typename V>
bool operator==(typename A<T>::template B<V> left,
                typename A<T>::template B<V> right) {...}

但我建议:

template <typename T, typename V>
using operator_type = typename A<T>::template B<V>;

template <typename T, typename V>
bool operator==(operator_type<T, V> left,
                operator_type<T, V> right) {...}

作为减轻所需的一些深奥语法的手段。这是一个奇怪的一次性的东西,你会期望typename足以表示::B是A的依赖名,但你仍然需要template关键字,因为解析器在处理<>时会出了名的混淆。This answer很好地解释了原因:
在name lookup(3.4)发现一个name是一个template-name之后,如果这个name后面跟一个<,<总是被当作一个template-argument-list的开头,而永远不会被当作一个name后面跟一个小于运算符。
现在我们回到了与typename相同的问题。如果我们在解析代码时还不能知道这个名字是否是一个模板,该怎么办?我们需要在模板名称前插入模板,如14.2/4所述。这看起来像:
t::template f<int>(); // call a function template

vlf7wbxs

vlf7wbxs2#

直接的方法typename A<T>::template B<V> left不能按预期工作,因为A<T>::是一个嵌套的名称说明符,它是一个非推导的上下文。T必须显式传递:operator==<int>(a, b)
为了保持==可用作二元运算符,可以使用SFINAE实现一个离线非成员声明:

template <typename T>
struct A {
  template <typename V>
  struct B {
    using ABT = T;
    using ABV = V;
  };
};

template <typename AB>
std::enable_if_t<
    std::is_same_v<AB, typename A<typename AB::ABT>::template B<typename AB::ABV>>,
    bool
> operator==(AB left, AB right) {
  return true;
}

godbolt上的完整示例:点击。

u0njafvf

u0njafvf3#

您可以有内联友元声明和大纲定义

template<typename T>
struct A
{
    template<typename V>
    struct B
    {
        friend bool operator==(B left, B right);
    };
};

template <typename T, typename V>
bool operator==(typename A<T>::template B<V> left, typename A<T>::template B<V> right)
{
    return true;
}

然而gcc警告说
warning:friend declaration bool operator==(A<T>::B<V>, A<T>::B<V>)声明了一个非模板函数[-Wnon-template-friend]
注意:(如果这不是你想要的,请确保函数模板已经被声明,并在函数名后面添加<>
为了修复这个警告,我们必须在B的定义之前转发声明operator==(B left, B right),这只能在A内部,这将迫使它也成为A的朋友。

相关问题