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
)?@happygreen绑架抱歉,我无法准确回答您的问题。您的具体困惑是什么?为什么编译器没有看到@HappyGreenDiamps编译器确实看到了它,也就是说,它是通过名称查找找到的。但是模板参数identity
不能从函数参数中推导出来,调用失败。对于第一个解决方案,我们显式指定模板参数以绕过推导。对于第二个解决方案,我们制作了T
operatorhank you@songyuanyao。非常感谢关于非推断上下文的链接。另外,非常感谢您以两种不同的方式解决此问题。你能详细说明一下混乱发生在哪里吗。
重载是针对我的代码的(就像std::ostream
和good
示例中解释的bad
)?@happygreen绑架抱歉,我无法准确回答您的问题。您的具体困惑是什么?为什么编译器没有看到@HappyGreenDiamps编译器确实看到了它,也就是说,它是通过名称查找找到的。但是模板参数identity
不能从函数参数中推导出来,调用失败。对于第一个解决方案,我们显式指定模板参数以绕过推导。对于第二种解决方案,我们制作了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; }