Определите функцию друга вне определения класса, когда класс и функция имеют отдельные параметры шаблона - PullRequest
0 голосов
/ 01 мая 2018

Следующий код прекрасно компилируется (просто минимальный пример, реальный код имеет больше причин для этого конкретного макета):

template<int A>
class Foo {
    template<int B>
    friend int bar(Foo<A> a, Foo<B> b) {
        return A * B;
    }
};

int main() {
    return bar(Foo<0>(), Foo<1>());
}

Однако я хотел бы отделить объявление от определения и поместить определение функции вне определения класса. Я попытался сделать это так, как вы сделали бы для функции-члена:

template<int A> template<int B>
int bar(Foo<A> a, Foo<B> b) {
    return A * B;
}

Но это не скомпилируется, потому что это не правильный синтаксис:

error: too many template-parameter-lists

Однако объединение двух списков параметров шаблона в этом определении (template<int A, int B>) приводит к ошибке компоновщика:

undefined reference to `int bar<1>(Foo<0>, Foo<1>)'

Это наводит меня на мысль, что другие списки параметров шаблона заставляют компилятор / компоновщик интерпретировать определение bar как функцию, отличную от объявления.

Итак, мой вопрос: как я могу определить функцию друга вне определения класса, когда класс и функция имеют отдельные параметры шаблона?

1 Ответ

0 голосов
/ 01 мая 2018

Я думаю, что нет способа сделать это. Ну, есть, но не в общем. Вы всегда можете явно записать перегрузки для каждого A:

template<int B>
int bar(Foo<0> a, Foo<B> b) {
    return 0 + B;
}

По сути, причина в том, что для каждого экземпляра Foo определяется разная перегрузка bar. Например, для Foo<0> вы получите

template<int B>
int bar(Foo<0>, Foo<B>);

Для каждого экземпляра Foo вы получите новый шаблон bar. Все эти bar независимы, потому что они используют параметр шаблона, который существует вне самого bar (из внешнего шаблона).

Вы не можете использовать двойной синтаксис template<>, потому что это будет означать, что у вас есть две вещи (класс, функция, ...), которые являются шаблоном. Это не тот случай, поскольку в качестве шаблона у вас есть только bar. Для первого / второго ничего нет template<>.

Вы не можете объединить их, потому что, как вы видели, вы получите другую функцию. Если вы посмотрите на экземпляр bar выше для Foo<0>, вы увидите, что это отличается от:

template<int A, int B>
int bar(Foo<A>, Foo<B>);

Созданная версия всегда будет лучше соответствовать, поскольку для первого параметра не нужно ничего выводить.

...