当类和函数具有单独的模板参数时,在类定义之外定义友元函数

Define friend function outside class definition when the class and function have separate template parameters

本文关键字:函数 定义 友元 参数 单独      更新时间:2023-10-16

下面的代码编译得很好(只是一个最小的例子,实际代码有更多的原因(:

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的定义解释为与声明不同的函数。

所以我的问题是:当类和函数具有单独的模板参数时,如何在类定义之外定义友元函数?

我认为没有办法做到这一点。嗯,有,但不是一般的。您始终可以为每个A显式编写重载:

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

基本上,原因是为每个实例化定义了不同的bar重载Foo。例如,对于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>);

实例化版本将始终是更好的匹配,因为它不必为第一个参数推断任何内容。