Объявление оператора == для вложенного шаблона класса

У меня есть следующий вложенный класс шаблона внутри другого класса шаблона:

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

Какой будет подпись не члена operator== для вложенного типа B? Следующая наивная попытка не работает:

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

3 ответа

Прямой подход,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: нажмите.

Ошибка не слишком далека, так как вам нужно ключевое слово 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, но вам все еще нужно ключевое слово шаблона, потому что синтаксический анализатор, как известно, запутывается при работе с < а также >, Этот ответ довольно неплохо объясняет, почему:

После того, как name lookup (3.4) обнаружит, что имя является именем шаблона, если за этим именем следует символ <, то <всегда берется как начало списка аргументов шаблона, а не как имя, за которым следует меньше чем оператор.

Теперь мы вернулись к той же проблеме, что и с typename. Что если мы еще не можем знать, является ли имя шаблоном при разборе кода? Нам нужно будет вставить шаблон непосредственно перед именем шаблона, как указано в 14.2/4. Это выглядит так:

t::template f<int>(); // call a function template

Вы можете иметь встроенную декларацию друга и определение схемы

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 предупреждает

предупреждение: объявление друга bool operator==(A<T>::B<V>, A<T>::B<V>) объявляет не шаблонную функцию [-Wnon-template-friend]

примечание: (если это не то, что вы хотели, убедитесь, что шаблон функции уже объявлен и добавьте <> после имени функции здесь)

И чтобы исправить это предупреждение, мы должны были бы operator==(B left, B right) до определения B, который может быть только внутри Aчто заставит его быть другом A также.

Другие вопросы по тегам