2016-03-07 45 views
3

下面的示例是我遇到的模板问题的蒸馏版本 - 请参阅下面的编译错误。如何重载operator <<以输出在模板内定义的向量?

#include <iostream> 
#include <vector> 

template <class T> struct S 
{ 
    typedef std::vector<T> SVec; 
}; 

template <class T> std::ostream& operator<<(std::ostream& OS, const S<T>::SVec& X) 
{ 
    for (const auto& e: X) OS << e << ' '; 
    return OS; 
} 

int main() 
{ 
    S<int>::SVec v; 
    std::cout << v << std::endl; 
} 

编译器输出:

g++ -g -Wall -O4 -std=c++11 -c tc041.cpp 
tc041.cpp:22:69: error: need ‘typename’ before ‘S<T>::SVec’ because ‘S<T>’ is a dependent scope 
template <class T> std::ostream& operator<<(std::ostream& OS, const S<T>::SVec& X) 

等等 - 数百行。 我的编译器 - g ++ 5.2.1,OS - Xubuntu 4.2.0。

如何使该运算符能够正确编译?

+0

错误消息其实是非常字面,尽管它需要一些更多的知识去了解它。 –

回答

3

有两个问题:

  • 在缺少运算符声明typename关键字。
  • 模板类型扣除在main中失败。

template <class T> 
std::ostream& operator<<(std::ostream& OS, const typename S<T>::SVec& X) 

typename关键字应S<T>::SVec之前。由于语言规则,编译器不知道SVec是否是成员类型或其他。 typename关键字是告诉编译器它是一个类型。

有关的语言规则的详细信息,可参考:http://en.cppreference.com/w/cpp/language/dependent_name


(注:我其实它不太确定,因为这个场景是我新太)

让我们做一个实验。我们不用函数语法调用operator<<,而是用函数语法调用它。

operator<< (std::cout, v); 

那么,它仍然失败。

如果我们用显式模板参数调用它会怎样?

operator<< <int> (std::cout, v); 

它的工作原理!那么,实际上,可能会工作。我发现一些标准库头可能包含干扰它的内容。但让我们把它放在一边。

本实验演示的问题是模板参数推演失败。无法推导出形式为class-template-name<T>::member-type的参数类型。

详情:http://en.cppreference.com/w/cpp/language/template_argument_deduction

+0

谢谢,它有帮助。有什么方法可以“帮助”编译器推断出这个论点? – HEKTO

+0

@HEKTO我没有一个好的解决方案。你可以考虑使用'std :: vector '或'S '。 –