在模板 class 中声明 non-template 函数?

Declare non-template function in a template class?

NOTE: this post is different from this one: Declare non-template friend function for template class outside the class, so please read my question before marking it as duplicate.

我想在 class 模板中声明一个 non-template 友元函数,该友元函数的参数和 return 类型 无关 到模板参数。我应该怎么做?

请注意它与之前的问题不同,因为在那个问题中,那个友元函数的参数和return类型是相关的 到模板参数。

示例,改编自上述问题:

// class.h
#include <iostream>
using namespace std;

template <typename T>
struct B
{
    T value;
    int value2;
    B() : value2(1) {}
    friend void modify(const int&); // unrelated to T!
    void printValue2() {
        modify(value2);
        cout << value2 << endl;
    }   
};

// define friend function foo() in a class.cpp file, not in the header
void modify(const int &v) { v = v * 2 + 1; } // HOW should I write it?

// main.cpp
int main() {
   B<int> b;
   b.printValue2();
   return 0;
}

我知道我可以在这个模板外声明 modify() class,这样它就变成了普通的普通函数。但我只希望此模板 class 可以访问 modify()。或者,为了实现访问控制的这一目标,我可以将 modify() 定义为此模板 class 中的静态方法,但这会使该方法成为模板方法,迫使我将其定义在 header.

跟进:如果上面的朋友方法不行,我应该如何同时实现两个目标:

已接受答案

要实现上述两个目标,请不要滥用友谊。

最好的做法是让class模板私下继承一个non-template基础class,并在那个基础class 声明与模板参数无关的通用 non-template 方法

因此,您可以在单独的 *.cpp 文件中定义这些方法,从而减小 header 的大小。

你这样做:

// class.cpp
void modify(const int &v) { v = v * 2 + 1; }

你实际上是在滥用友谊,但是没关系。这意味着您需要解决使用 friend 声明函数的含义:它仅通过 ADL 可见!现在 没有 方式来引用 modify,因为 modify 不依赖于 B,所以 B 的作用域从未搜索名为 modify.

的函数

有一个解决方法,但不是很好。您需要在每个使用它的函数中声明 modify 。您也可以在全局范围内声明它,然后每个人都可以调用它。或者,您始终可以在 detail 命名空间中声明它(但这有点相同的问题):

template<typename T>
void B<T>::printValue2() {
    void modify(const int&);
    modify(value2);
    cout << value2 << endl;
}

正如我在评论中所说,friendship 控制对 class 的访问。只要你的函数 modify() 是一个独立的函数,它就不能成为好友。因为您想从模板中调用它,所以它也不能隐藏在 .cpp 文件中,但必须在 class 模板 B 及其成员使用 modify().[= 的定义中可见。 17=]

一个解决方案是将 modify 作为 static 方法放在辅助非模板 class 中,这反过来与模板 B<>.[=17 成为朋友=]

// file foo.h (header)

namespace foo {
    template<typename> class B;            // forward declaration

    class exclusive_for_B
    {
        template<typename T>
        friend class B<T>;

        static void modify(int&x)          // must take int&, not const int&
        { x &= x+42; }
    };

    template<typename T>
    class B
    {
        int val;
     public:
        ...
        void printvalue()
        {
            exclusive_for_B::modify(val);  // access via friendship
            std::cout << val << '\n';
        }
    };
}

您可能会使用私有继承而不是友谊:

// class.h
#include <iostream>

class B_helper
{
protected:
    static void modify(int &v);
};

template <typename T>
struct B : private B_helper
{
    T value;
    int value2;
    B() : value2(1) {}

    void printValue2() {
        modify(value2);
        std::cout << value2 << std::endl;
    }   
};

// class.cpp
void B_helper::modify(int &v) { v = v * 2 + 1; }