在模板类中声明非模板功能?

时间:2018-08-09 21:52:13

标签: c++ friend-function

  

注意:这篇文章与这篇文章不同Declare non-template friend function for template class outside the class,因此请先阅读我的问题,然后再将其标记为重复。

我想在类模板中声明一个非模板朋友函数,并且该朋友函数的参数和返回类型与模板参数不相关。我该怎么办?

请注意,它与之前的问题不同,因为在该问题中,该朋友函数的参数和返回类型与模板参数相关

示例,从上面的问题改编而成:

// 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(),以使其成为普通的普通函数。但我只希望该模板类可以访问modify()。或者,为了实现访问控制的目标,我可以在此模板类中将modify()定义为静态方法,但这将使该方法成为模板方法,迫使我在标头中对其进行定义。

后续行动:如果上述的朋友方法不起作用,我应该如何同时实现两个目标:

  • 访问控制:只有该类模板才能访问modify()
  • 能够在* .cpp文件中而不是在标头中定义modify()

接受的答案

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

最佳做法是让类模板私下继承非模板基类,并在该基类中声明与模板无关的常见非模板方法争论。

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

3 个答案:

答案 0 :(得分:3)

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

// 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; }

答案 1 :(得分:0)

您这样做:

// 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;
}

答案 2 :(得分:0)

正如我在评论中所说,friend ship控制着对一个类的访问。只要您的函数modify()是独立函数,就不能成为朋友。您想从模板调用它时,也不能将其隐藏在.cpp文件中,但必须在类模板B及其成员使用modify()的定义中可见。

一种解决方案是将modify作为static方法放入辅助非模板类中,该类又与模板B<>成为朋友。

// 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';
        }
    };
}