c++ - 如何定义在两个类之外的模板类内部的非模板类中声明的友元函数?

标签 c++ c++11 templates inner-classes friend

我找到了“如何在其声明之外定义模板类的友元模板函数”(SO/cppreference),但如果我们在混合中添加另一个内部非模板类,该怎么做?

即如何(外部)定义 operator<<class Internal 中声明来自以下示例:

#include <iostream>

template <typename T>
class External {
public:
    explicit External(T initial) : value{initial} {}
    class Internal {
    public:
        Internal(const External& e) : internal_value{e.value} {}

    private:        
        friend std::ostream& operator<<(std::ostream& os, const Internal& i);
        // ^^^ this one
        /* body
        {
            return os << i.internal_value;
        }
        */

        T internal_value;
    };

    friend std::ostream& operator<<(std::ostream& os, const External& e)
    {
        return os << Internal{e};
    }
private:
    T value;
};

int main()
{
    std::cout << External<int>{5};
}

最佳答案

问题来了。尽管 External 是模板而 Internal 是依赖类型。 friend 函数本身不是模板化的。看起来很奇怪,它不依赖于模板参数。

当您以内联方式定义它时,模板的每个特化也会创建关联的友元函数。但是当它不是内联时,您需要为每个特化明确提供运算符的定义。你不能用模板来做到这一点,因为函数不是模板。

因此,如果您在模板声明之后添加:

std::ostream& operator<<(std::ostream& os, External<int>::Internal const& i)
{
    return os << i.internal_value;
}

它将构建。如您所见,函数中只使用了具体类型。

显然这不是一个很好的解决方案。任何明智的人都希望 External 的特化来生成好友定义。以可维护的方式实现这一点的方法是保持运算符定义内联,但不是在那里完成工作,而是委托(delegate)给成员函数(它依赖于模板参数):

class Internal {
public:
    Internal(const External& e) : internal_value{e.value} {}

private:
    std::ostream& print(std::ostream&) const;
    friend std::ostream& operator<<(std::ostream& os, Internal const& i)
    {
        return i.print(os); // Short and sweet on account of being inline
    }

    T internal_value;
};

//....

template<typename T>
std::ostream& External<T>::Internal::print(std::ostream& os) const {
   // Provided outside of the class definition, can be as verbose as you like
   return os << internal_value;
}

关于c++ - 如何定义在两个类之外的模板类内部的非模板类中声明的友元函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46211600/

相关文章:

c++ - 尽量减少 Zip-to-Barcode 程序中的重复代码

c# - 指向 native C++ 堆的指针上的 Marshal.PtrToStructure 是否正常?

c++ - QXmlStreamReader读取空文本,文档肯定不为空

c++ - 实现简单的分配器

c++ - 从 C++ 中的 exec 命令获取字符串输出

google-app-engine - GAE Go 模板包中的条件语句

c++ - 为什么在未评估的操作数内进行包扩展会导致最后一个元素?

c++ - C++ 中的 "using"关键字

c++ - 如何使用模板特化来查找成员函数参数类型等?

c++ - C++ 中 class = void 的用途?