在标头之间调用时,模板实例化无法匹配重载流运算符的参数列表
Posted
技术标签:
【中文标题】在标头之间调用时,模板实例化无法匹配重载流运算符的参数列表【英文标题】:Template instantiation unable to match argument list for overloaded stream operator when invoked between headers 【发布时间】:2016-09-30 10:45:06 【问题描述】:注意:以前我没有遇到过这个问题!我的 to_string 方法工作得很好,模板实例化为我的 Point 类找到了正确的重载,我已经使用它几个月了!然而,最后一次提交出了点问题,在一个源文件中我收到了这个众所周知的错误消息(仅在这个源文件中,在其他地方 mx::to_string(mx::Point) 可以正常工作)。我无法弄清楚可能是什么原因,因为我没有注意到任何可能会搞砸的线路。
Plus 已经扫过所有有关流运算符重载的相关问题,但没有找到解决方案。
所以我有一个点类:
#ifndef MXBASIC_UTILITIES_H
#define MXBASIC_UTILITIES_H
#include <ostream>
#include <string>
namespace mx
class Point;
class mx::Point
public:
Point();
Point(int x, int y);
int getX() const;
int getY() const;
int& getX();
int& getY();
//...
;
inline mx::Point::Point() : _x(0), _y(0)
inline mx::Point::Point(int x, int y) : _x(x), _y(y)
inline int mx::Point::getX() const return _x;
inline int mx::Point::getY() const return _y;
inline int& mx::Point::getX() return _x;
inline int& mx::Point::getY() return _y;
// THE OVERLOAD:
inline std::ostream& operator<<(std::ostream& os, const mx::Point& point)
return os << '(' << point.getX() << ',' << point.getY() << ')';
#endif
一个名为 helpertypes.h 的头文件,其中有我的 to_string 函数:
#ifndef HELPERTYPES_H
#define HELPERTYPES_H
#include <iostream>
#include <cstdint>
#include <memory>
#include <sstream>
#include <string>
// ...
namespace mx
template<typename T>
std::string to_string(const T& val)
std::ostringstream os;
os.flags(std::ios::fixed);
os.precision(2);
os << val; // getting error here as of recently, both in MinGW 4.7.3 and MSVC15
return os.str();
#endif
完整的错误信息: 在这里阅读更多:pastebin.com/gFdFezrV
MSVC15:
2>c:(...)\classes\helpertypes.h(87): 错误 C2679: 二进制 ' c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(495):注意: 可能是 'std::basic_ostream> &std::basic_ostream>::运算符 *)' 2> c:\程序文件(x86)\微软视觉工作室 14.0\vc\include\ostream(475): 注意: 或 'std::basic_ostream> &std::basic_ostream>::operator c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(455):注意:或 'std::basic_ostream> &std::basic_ostream>::operator c:\program 文件 (x86)\microsoft visual studio 14.0\vc\include\ostream(435):注意:或 'std::basic_ostream> &std::basic_ostream>::operator c:\程序文件(x86)\微软视觉工作室 14.0\vc\include\ostream(415):注意:或 'std::basic_ostream> &std::basic_ostream>::operator c:\程序文件(x86)\微软视觉工作室 14.0\vc\include\ostream(395):注意:或 'std::basic_ostream> &std::basic_ostream>::操作符 c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(375): note: or 'std::basic_ostream> &std::basic_ostream>::运算符 c:\program 文件 (x86)\microsoft visual studio 14.0\vc\include\ostream(355):注意:或 'std::basic_ostream> &std::basic_ostream>::操作符 c:\program 文件 (x86)\microsoft visual studio 14.0\vc\include\ostream(335):注意:或 'std::basic_ostream> &std::basic_ostream>::operator c:\程序文件(x86)\微软视觉工作室 14.0\vc\include\ostream(315):注意:或 'std::basic_ostream> &std::basic_ostream>::操作符 c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(290):注意:或 'std::basic_ostream> &std::basic_ostream>::operator c:\程序文件(x86)\微软视觉工作室 14.0\vc\include\ostream(270):注意:或 'std::basic_ostream> &std::basic_ostream>::操作符 c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(236):注意:或 'std::basic_ostream> &std::basic_ostream>::operator c:\程序文件(x86)\微软视觉工作室 14.0\vc\include\ostream(216):注意:或 'std::basic_ostream> &std::basic_ostream>::运算符 c:\程序文件(x86)\微软视觉工作室 14.0\vc\include\ostream(209):注意:或 'std::basic_ostream> &std::basic_ostream>::运算符 c:\program 文件 (x86)\microsoft visual studio 14.0\vc\include\ostream(202):注意:或 'std::basic_ostream> &std::basic_ostream>::运算符 &(__cdecl *)(std::basic_ios> &))' 2> c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(196): 注意:或 'std::basic_ostream> &std::basic_ostream>::运算符 &(__cdecl *)(std::basic_ostream> &))' 2> c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(692): 注意:或 'std::basic_ostream> &std::运算符 (std::basic_ostream> &,const char *)' 2> c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(739): 注意: 或 'std::basic_ostream> &std::operator (std::basic_ostream> &,char)' 2> c:\program 文件 (x86)\microsoft visual studio 14.0\vc\include\ostream(777): 注意: 或 'std::basic_ostream> &std::operator (std::basic_ostream> &,const char *)' 2> c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(824): 注意: 或 'std::basic_ostream> &std::operator (std::basic_ostream> &,char)' 2> c:\program 文件 (x86)\microsoft visual studio 14.0\vc\include\ostream(950): 注意: 或 'std::basic_ostream> &std::operator (std::basic_ostream> &,const signed char *)' 2> c:\program files (x86)\microsoft visual 工作室 14.0\vc\include\ostream(957):注意:或 'std::basic_ostream> &std::operator (std::basic_ostream> &,signed char)' 2> c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(964): 注意: 或 'std::basic_ostream> &std::operator (std::basic_ostream> &,const unsigned char *)' 2> c:\program files (x86)\microsoft visual 工作室 14.0\vc\include\ostream(971):注意:或 'std::basic_ostream> &std::operator (std::basic_ostream> &,unsigned char)' 2> c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(981): 注意: 或 'std::basic_ostream> &std::operator (std::basic_ostream> &&,const _Ty &)' 2> 与 2> [ 2> _Ty=mx::Point 2> ] 2> c:\program files (x86)\microsoft visual studio 14.0\vc\include\ostream(1019):注意:或 'std::basic_ostream> &std::operator (std::basic_ostream> &,const std::error_code &)' 2> c:\program files (x86)\microsoft Visual Studio 14.0\vc\include\random(2568):注意:或 'std::basic_ostream> &std::operator (std::basic_ostream> &,const std::bernoulli_distribution &)' 2> c:\program 文件 (x86)\microsoft visual studio 14.0\vc\include\thread(246):注意:或 'std::basic_ostream> &std::operator (std::basic_ostream> &,std::thread::id)' 2> c:(...)\classes\helpertypes.h(87): 注意: 在尝试匹配参数列表时 '(std::ostringstream, const mx::点)' 2> c:(...)\classes(...)\entity\tinyent\tinyent.cpp(1502):注意:见 引用函数模板实例化 'std::string mx::to_string(const T &)' 正在编译 2> 2> [ 2> T=mx::点 2> ]
MinGW 4.7.3:
在 jni/../../Classes/utilities/pattern/pat.h:5:0 包含的文件中, 来自 jni/../../Classes/(...)/entity/tinyent/../ent.h:3, 来自 jni/../../Classes/(...)/entity/tinyent/tinyent.h:2, 来自 jni/../../Classes/(...)/entity/tinyent/tinyent.cpp:1: jni/../../Classes/helpertypes.h:在 'std::string 的实例化中 mx::to_string(const T&) [with T = mx::Point;标准::字符串 = std::basic_string]': jni/../../Classes/(...)/entity/tinyent/tinyent.cpp:1502:20:需要 从这里 jni/../../Classes/helpertypes.h:87:5: 错误:无法绑定 'std::basic_ostream' 左值到 'std::basic_ostream&&' 操作系统 & 的参数 1 std::operator&&, const _Tp&) [与_CharT = char; _Traits = std::char_traits; _Tp = mx::点]' 运算符&& __os, const _Tp& __x) ^
触发实例化的位置:
tinyent.h
#pragma once
#include <string>
#include "ent.h"
#include "mxbasic_utilities.h" // definition of my overload included!
class TinyEnt : public Ent
public:
// ...
virtual std::string toString() const override;
private:
// ...
int _posX, posY;
;
tinyent.cpp
#include "tinyent.h"
// ...
std::string toString() const
return std::string("TinyEnt ") + mx::to_string(id()) + " at " // decltype(id()) is ULL, no problem here
+ mx::to_string(mx::Point(_posX, _posY)); // place of instantiation, overload not found
如果我将我的 to_string 函数的定义放在这个 toString 函数的前面,它就可以工作:
备用tinyent.cpp
#include "tinyent.h"
template<typename T>
std::string to_string(const T& val)
std::ostringstream os;
os.flags(std::ios::fixed);
os.precision(2);
os << val;
return os.str();
std::string toString() const
return std::string("TinyEnt ") + mx::to_string(id()) + " at "
+ ::to_string(mx::Point(_posX, _posY)); // no problems this way
我完全不知道该怎么办。我已经检查了包含 如果可能存在递归包含,则没有层次结构(helpertypes.h 仅取决于 stl 标头)。我尝试从地面 0 重建,并尝试使用不同的编译器。您是否有任何提示可能出了什么问题?
编辑:
在我的 mx::to_string 函数中使用完整的命名空间限定条件时(如:::operator(os, val);
),我收到不同的错误消息。当使用 size_t (在这种情况下为 unsigned int )时,实例化会引发歧义错误,就好像在第一轮参数查找中没有找到它一样。
MSVC15 和 MinGW 产生的错误信息。
在 jni/../../Classes/utilities/pattern/pat.h:5:0 包含的文件中, 来自 jni/../../Classes/patmgr.h:4, 来自 jni/../../Classes/patmgr.cpp:1: jni/../../Classes/helpertypes.h: 在 'std::string 的实例化中 mx::to_string(const T&) [with T = unsigned int;标准::字符串 = std::basic_string]': jni/../../Classes/utilities/pattern/pat_bit_spec.h:185:37:必需 从这里 jni/../../Classes/helpertypes.h:94:22: 错误:调用 重载 'operator
在这个部分: 错误:重载 'operator
【问题讨论】:
明确一点:你的 helpertypes.h (仍然)是否包含带有operator<<
定义的头文件?
另外,您可以尝试将您的行 os << val
更改为(完全命名空间限定)ms::operator<<(os, val)
以查看问题所在
helpertypes.h 不需要包含重载运算符的定义,这是实例化的工作。完全限定的命名空间将是 ::operator
同意它不需要查看定义,但它确实至少需要查看一个声明,该声明必须出现在编译单元比 helpertypes.h 中的to_string()
函数。尝试在您的 to_string()
声明上方添加行 std::ostream& operator<<(std::ostream& os, const mx::Point& point);
以确认/反驳这一点
我尝试了前向声明,遗憾的是没有解决。有趣的是,如果我使用 ::operator
【参考方案1】:
由于某种原因,编译器认为它不会再考虑我在全局命名空间中定义的重载。然后我尝试在与朋友相同的命名空间中定义重载,但后来我得到了这些歧义错误。引发歧义错误是因为我留下了重载的前向声明,就好像它是在全局命名空间中定义的,而不是在 mx:: 命名空间中。一旦我删除了前向声明并让编译器利用 ADL 的力量,看在上帝的份上,它编译了。
为什么在全局命名空间中查找重载失败(以及为什么只在一个编译单元中)对我来说仍然是一个长期的谜。
故事的寓意: 从现在开始,我只会在类所在的同一个命名空间中声明运算符重载。
【讨论】:
以上是关于在标头之间调用时,模板实例化无法匹配重载流运算符的参数列表的主要内容,如果未能解决你的问题,请参考以下文章