代码之家  ›  专栏  ›  技术社区  ›  Leedehai

在模板类中声明非模板函数?

  •  1
  • Leedehai  · 技术社区  · 6 年前

    注意 :此帖子是 和这个不同 : Declare non-template friend function for template class outside the class ,所以在将问题标记为副本之前,请先阅读我的问题。

    我想在类模板中声明一个非模板friend函数,该friend函数的参数和返回类型是 无关的 到模板参数。我该怎么做?

    请注意,它与上一个问题不同,因为 那个问题 ,friend函数的参数和返回类型为 相关的 到模板参数。

    根据上述问题改编的示例:

    // 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() 在这个模板类之外,所以它变成了一个普通的函数。但我只希望这个模板类可以访问 修改() . 或者,为了实现这个访问控制的目标,我可以定义 修改() 在这个模板类中是一个静态方法,但这会使该方法成为一个模板方法,迫使我在头中定义它。

    改善效果追踪 :如果上面的朋友方法不起作用,我应该如何同时实现这两个目标:

    • 访问控制:只有类模板可以访问 修改()
    • 能够定义 修改() 在*.cpp文件中,而不是在头中。

    接受的答案 :

    为了实现以上两个目标,不要滥用友谊。

    最佳实践是让类模板私有地继承 非模板基类 ,并在基类中声明common 非模板方法 与模板参数无关的。

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

    3 回复  |  直到 6 年前
        1
  •  3
  •   Jarod42    6 年前

    你可以用私人继承代替友谊:

    // 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; }
    
        2
  •  0
  •   Rakete1111    6 年前

    你这样做:

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

    你实际上是在滥用友谊,但没关系。这意味着您需要解决如何使用 friend :仅通过ADL可见!现在有了 参考方法 modify ,因为 修改 不依赖于 B ,所以 的作用域从不搜索名为 修改 .

    有工作要做,但不好看。你需要申报 修改 在你使用它的每个函数中。您也可以在全局范围内声明它,但之后每个人都可以调用它。或者,您可以在 detail 命名空间(但这有一点相同的问题):

    template<typename T>
    void B<T>::printValue2() {
        void modify(const int&);
        modify(value2);
        cout << value2 << endl;
    }
    
        3
  •  0
  •   Walter    6 年前

    正如我在评论中所说, friend ship控制类的访问。只要你履行职责 modify() 是一个独立的函数,不能成为好友。正如您希望从模板调用它一样,它也不能隐藏在.cpp文件中,但必须在类模板B及其成员的定义中使用 修改() .

    一个解决方案是 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';
            }
        };
    }
    
    推荐文章