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

时间:2018-05-01 08:20:20

标签: c++ templates friend

以下代码编译得很好(只是一个最小的例子,实际代码有更多这种特定布局的原因):

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 :(得分:2)

我认为没有办法做到这一点。那么有但不是一般的。您始终可以为每个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>);

实例化版本总是更好的匹配,因为它不必为第一个参数推导出任何东西。