[英]C++ weird templates/namespaces behavior
I had a problem compiling my code since it wasn't able to find a matching function on a template.我在编译代码时遇到问题,因为它无法在模板上找到匹配的函数。 I've narrowed down the problem to this example:
我已经将问题缩小到这个例子:
namespace cv
{
class FileNode
{ };
template<typename _Tp> static inline void operator >> (const FileNode& n, _Tp& value)
{
read(n, value, _Tp());
}
static inline void read(const FileNode& node, bool& value, bool default_value)
{ }
}
class K
{ };
namespace D
{
class A
{ };
}
template<class X>
static void read(const cv::FileNode& node, X& x, const X& default_value)
{
return;
}
using namespace D;
class B
{
void read(const cv::FileNode& fn)
{
A a;
fn >> a;
}
};
int main(int argc, char* argv[]) { }
On Gcc 9.10 I get the following error:在 Gcc 9.10 上,我收到以下错误:
invalid initialization of reference of type 'bool&' from expression of type 'D::A' { read(n, value, _Tp()); }
On Visual Studio 2019:在 Visual Studio 2019 上:
Error C2664 'void cv::read(const cv::FileNode &,bool &,bool)': cannot convert argument 2 from '_Tp' to 'bool &'
I've found any of the following changes will make the code compiling:我发现以下任何更改都会使代码编译:
class A
-> class A : public K
class A
-> class A : public K
read
specialization for bool
bool
read
专业化cv
namespacecv
命名空间read
template inside namespace D
read
模板移动到命名空间D
Unfortunately, none of the previous fixes is applicable to my original problem and I still don't really have an actual understanding on why exactly it's not able to find the read
template.不幸的是,以前的修复程序都不适用于我原来的问题,我仍然没有真正理解为什么它无法找到
read
模板。
ADL strikes back: ADL反击:
in在
template<typename _Tp> static inline void operator >> (const FileNode& n, _Tp& value)
{
read(n, value, _Tp());
}
read
is undeclared, so can only be found by ADL read
未声明,因此只能由ADL找到
So it will search in namespace associated to FileNode
(so cv
), and the ones associated to _Tp
.因此,将在相关联的命名空间中搜索
FileNode
(这样cv
),以及相关联的那些_Tp
。
when _Tp
is D::A
, it would be namespace D
.当
_Tp
是D::A
,它将是命名空间D
。
and the only possible overload of read
is cv::read
which take bool
.而
read
唯一可能的重载是cv::read
,它采用bool
。
Moving declaration of read<T>
above cv::operator >>
solve the issue at it would also be considered with ADL.在
cv::operator >>
上面移动read<T>
声明,解决这个问题也可以用 ADL 来考虑。
Normally, I would separate the classes and the namespaces to different .hpp files, which automatically, will force you to make the function:通常,我会将类和命名空间分开到不同的 .hpp 文件中,这将自动强制您创建函数:
template<typename _Tp> static inline void operator >> (const FileNode& n, _Tp& value)
To be declared before the namespaces which use it (like cv
).在使用它的命名空间之前声明(如
cv
)。
I think that the best way to avoid this kind of problems is to clean your code, and to make it as separate and independent as you can.我认为避免此类问题的最佳方法是清理您的代码,并使其尽可能独立和独立。 This way, whenever you want to use this unique
read
function in another namespaces, you won't need to put the new namespaces inside this file, or alternative include all the namespaces that are currently in this file.这样,每当您想在另一个命名空间中使用这个独特的
read
函数时,您就不需要将新的命名空间放在这个文件中,或者替代地包含当前在这个文件中的所有命名空间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.