C++ 当内部类使用外部类模板参数但仅当使用`ostream'时,编译失败`

C++ 当内部类使用外部类模板参数但仅当使用`ostream'时,编译失败`,c++,templates,inner-classes,C++,Templates,Inner Classes,当内部类使用外部类的模板参数时,我遇到了一个编译器错误,我在内部类型的成员上的外部类上实例化了一个输出流操作符 我花了很多时间试图解决这个问题。我相信下面的资料很接近,但我仍然不明白为什么我的编译会失败 代码如下: #include <iostream> #include <vector> template <typename T> struct Outer { struct Inner { Inner(const T

当内部类使用外部类的模板参数时,我遇到了一个编译器错误,我在内部类型的成员上的外部类上实例化了一个输出流操作符

我花了很多时间试图解决这个问题。我相信下面的资料很接近,但我仍然不明白为什么我的编译会失败

代码如下:

#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操作符,但您还是得到了编译错误,因为它导致模板参数推断失败

    在以下情况下,用于组合p的类型、模板和非类型值不参与模板参数推导,而是使用在别处推导或显式指定的模板参数。如果模板参数仅在非推导上下文中使用且未显式指定,则模板参数推导将失败

  • 使用限定id指定的类型的嵌套名称说明符(范围解析运算符左侧的所有内容::):

  • 例如,如果显式地(以丑陋的样式)指定模板参数,它将编译。在
    操作符中,您得到了编译错误,因为它导致模板参数推断失败

    在以下情况下,用于组合p的类型、模板和非类型值不参与模板参数推导,而是使用在别处推导或显式指定的模板参数。如果模板参数仅在非推导上下文中使用且未显式指定,则模板参数推导将失败

  • 使用限定id指定的类型的嵌套名称说明符(范围解析运算符左侧的所有内容::):
  • 例如,如果显式地(以丑陋的样式)指定模板参数,它将编译。在
    操作符中修复此问题

    std::cout << g.innerChildren_[i] << std::endl; // Line 51
    
    std::cout修复此问题

    std::cout << g.innerChildren_[i] << std::endl; // Line 51
    


    谢谢你的回答。虽然它解决了问题,但没有解释问题。有一位
    操作员,感谢您的更新/编辑。我仍然无法理解为什么编译器无法确定这一点(以及建议的代码更改如何告知编译器要选择什么重载定义)。谢谢您的回答。虽然它解决了问题,但没有解释问题。有一位
    操作员,感谢您的更新/编辑。我仍然无法理解为什么编译器无法确定这一点(以及建议的代码更改如何告知编译器要选择什么重载定义)。我已经承认(请参阅问题的最后一行)没有继承。是的,但是,在另一个类中声明一个类并不意味着它派生自任何东西。我想我理解你的意思,但似乎我需要澄清我的意思:我要问的是,为什么编译器假定
    Outer::internal
    意味着
    internal
    派生自
    Outer
    ?我明白了,为什么它不能是
    外部定义的类型呢。它并不假设-Outer的重载是可用的候选项之一,编译器会告诉您为什么不能使用它。模板错误消息并不有趣,即使它们比以前更好。我已经承认(见我问题的最后一行)没有继承。是的,但在另一个类中声明一个类并不能使它派生自任何东西。我想我理解你的意思,但我似乎需要澄清我所说的:我要问的是,为什么编译器假定
    Outer::internal
    意味着
    internal
    是从
    Outer
    派生出来的?我明白了,为什么它不能是
    外部定义的类型呢。它并不假设-Outer的重载是可用的候选项之一,编译器会告诉您为什么不能使用它。模板错误消息并不有趣,即使它们比以前更好。请欣赏有关非推断上下文的链接。另外,非常感谢您以两种不同的方式解决此问题。你能详细说明一下混乱发生在哪里吗。
    std::ostream
    重载是针对我的代码的(就像
    good
    bad
    示例中解释的
    identity
    )?@happygreen绑架抱歉,我无法准确回答您的问题。您的具体困惑是什么?为什么编译器没有看到@HappyGreenDiamps编译器确实看到了它,也就是说,它是通过名称查找找到的。但是模板参数
    T
    不能从函数参数中推导出来,调用失败。对于第一个解决方案,我们显式指定模板参数以绕过推导。对于第二个解决方案,我们制作了
    operatorhank you@songyuanyao。非常感谢关于非推断上下文的链接。另外,非常感谢您以两种不同的方式解决此问题。你能详细说明一下混乱发生在哪里吗。
    std::ostream
    重载是针对我的代码的(就像
    good
    bad
    示例中解释的
    identity
    )?@happygreen绑架抱歉,我无法准确回答您的问题。您的具体困惑是什么?为什么编译器没有看到@HappyGreenDiamps编译器确实看到了它,也就是说,它是通过名称查找找到的。但是模板参数
    T
    不能从函数参数中推导出来,调用失败。对于第一个解决方案,我们显式指定模板参数以绕过推导。对于第二种解决方案,我们制作了
    运营商@songyuanyao,非常感谢您。
    
    operator<< <T> (strm, g.innerChildren_[i]);
    //         ^^^
    
    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;
        }
    };
    
    std::cout << g.innerChildren_[i] << std::endl; // Line 51
    
    std::cout << g.innerChildren_[i].data_ << std::endl; // Line 51
    
    for (size_t i = 0; i < g.innerChildren_.size(); ++i)
    {
        operator<< <T>(strm, g.innerChildren_[i]);
        strm << std::endl;
    }