【发布时间】:2020-07-04 15:35:51
【问题描述】:
当内部类使用外部类的模板参数时遇到编译器错误,我在内部类型的成员上实例化外部类的输出流运算符。
我花了很多时间试图解决这个问题。我相信以下来源很接近,但我仍然不明白为什么我会遇到编译失败。
- 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>’? (是的,没有继承,但是内部类型定义嵌套在外部)
【问题讨论】:
-
我已经承认(见我问题的最后一行)没有继承。
-
是的,但是在另一个类中声明一个类不会使它派生自任何东西。
-
我想我明白你在说什么,但似乎我需要澄清我在说什么:我要问的是,为什么编译器会假设
Outer<int>::Inner表示Inner派生自Outer<int>?为什么它不能是Outer<int>中定义的类型——就像这里的情况一样? -
我明白了。它不假设 - Outer 的重载是可用的候选者之一,编译器会告诉你为什么不能使用它。模板错误消息并不有趣,即使它们比以前更好。
标签: c++ templates inner-classes