c++ - 内部类使用外部类模板参数时(仅当使用 `ostream`时)编译失败

标签 c++ templates inner-classes

当内部类使用外部类的template参数时,我会遇到编译器错误,并且我在内部类型的成员的外部类上实例化了一个输出流运算符。
我花了很多时间尝试解决此问题。我相信以下资料来源接近,但我仍然不明白为什么我编译失败。

  • https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types
  • https://msdn.microsoft.com/en-us/library/71dw8xzh.aspx

  • 这是代码:
    #include <iostream>
    #include <vector>
    
    template <typename T>
    struct Outer
    {
        struct Inner
        {
            Inner(const T& val = T());
            T data_;
        }; // end class Inner
    
        Outer();
    
        void AddInnerChildToOuter(const T& data);
        std::vector<typename Outer<T>::Inner> innerChildren_;
    }; // end class Outer
    
    
    // Inner constructor
    template <typename T>
    Outer<T>::Inner::Inner(const T& val) : data_(val)
    {
    }
    
    template <typename T>
    std::ostream& operator<<(std::ostream& strm, // Line 27
                             const typename Outer<T>::Inner& gn)
    {
        strm << gn.data_ << std::endl;
        return strm;
    }
    
    // Outer constructor
    template <typename T>
    Outer<T>::Outer()
    {
    }
    
    template <typename T>
    void Outer<T>::AddInnerChildToOuter(const T& data)
    {
        typename Outer<T>::Inner node(data);
        innerChildren_.push_back(node);
    }
    
    template <typename T>
    std::ostream& operator<<(std::ostream& strm, const Outer<T>& g)
    {
        for (size_t i = 0; i < g.innerChildren_.size(); ++i)
            std::cout << g.innerChildren_[i] << std::endl; // Line 51
        return strm;
    }
    
    int main()
    {
        Outer<int> g;
        g.AddInnerChildToOuter(3);
        g.AddInnerChildToOuter(5);
        std::cout << g << std::endl; // Line 60
        return 0;
    }
    
    我在外部得到ostream operator <<的编译器错误,该错误为内部调用了相应的输出流运算符。我没有发布编译器错误消息的全部内容;我认为是相关的。
    $ g++ -Wall -W -Wextra -pedantic -ansi OuterInnerArgh.cpp 
    OuterInnerArgh.cpp: In instantiation of ‘std::ostream& operator<<(std::ostream&, const Outer<T>&) [with T = int; std::ostream = std::basic_ostream<char>]’:
    OuterInnerArgh.cpp:60:18:   required from here
    OuterInnerArgh.cpp:51:19: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘const Outer<int>::Inner’)
             std::cout << g.innerChildren_[i] << std::endl;
             ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
    
    (扼杀了编译器在各种ostream重载中的尝试;下面有更多编译器错误消息)
    OuterInnerArgh.cpp:27:15: note: candidate: template<class T> std::ostream& operator<<(std::ostream&, const typename Outer<T>::Inner&)
     std::ostream& operator<<(std::ostream& strm,
                   ^~~~~~~~
    OuterInnerArgh.cpp:27:15: note:   template argument deduction/substitution failed:
    OuterInnerArgh.cpp:51:19: note:   couldn't deduce template parameter ‘T’
             std::cout << g.innerChildren_[i] << std::endl;
             ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
    OuterInnerArgh.cpp:48:15: note: candidate: template<class T> std::ostream& operator<<(std::ostream&, const Outer<T>&)
     std::ostream& operator<<(std::ostream& strm, const Outer<T>& g)
                   ^~~~~~~~
    OuterInnerArgh.cpp:48:15: note:   template argument deduction/substitution failed:
    OuterInnerArgh.cpp:51:19: note:   ‘const Outer<int>::Inner’ is not derived from ‘const Outer<T>’
             std::cout << g.innerChildren_[i] << std::endl;
             ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
    
    (其余的编译器错误已删除)
    请让我知道为什么遇到编译器错误-
  • 即使我有ostream operator <<typename Outer<T>::Inner&
  • 即使我在相关的
  • 上“撒上”了typename“magic-dust”
  • 仅适用于外部ostream运算符,不适用于构造函数或内部ostream运算符(后者可能根本没有实例化?)

  • 为什么编译器说‘const Outer<int>::Inner’ is not derived from ‘const Outer<T>’? (是的,没有继承,但是内部类型定义嵌套在外部内部)

    最佳答案

    由于non-deduced context导致模板参数推导失败,因此出现编译错误。

    In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

    1. The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:

    例如,如果您明确指定模板参数(丑陋的风格),它将进行编译。在operator<<Outer中:
    operator<< <T> (strm, g.innerChildren_[i]);
    //         ^^^
    
    您可以将operator<<设置为非模板(以绕过类型推导的麻烦),然后必须在类定义中将其定义为friend。例如
    struct Inner
    {
        Inner(const T& val = T());
        T data_;
        friend std::ostream& operator<<(std::ostream& strm,
                                        const Inner& gn)
        {
            strm << gn.data_ << std::endl;
            return strm;
        }
    };
    
    LIVE

    关于c++ - 内部类使用外部类模板参数时(仅当使用 `ostream`时)编译失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62731057/

    相关文章:

    c++ - 使用子类中的类型定义扩展模板类

    Java 泛型不兼容类型链表迭代器

    java - 从外部类引用内部类中的方法

    c++ - 基于链表的图,顶点可以有多个边吗?

    c++ - cmake:外部项目更新和离线工作

    c++ - 如何在 OpenCV 中找到 x 和 y 梯度?

    C++ - 重复使用 istringstream

    c++ - 如何返回定义明确的内存部分?例如图像数据中像素的颜色值

    c++ - 在 C 中使用局部变量创建类似于函数的 C++ 模板

    c++ - 模板类的内部类可以是非模板类吗?