简体   繁体   English

C++ 奇怪的模板/命名空间行为

[英]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
  • Delete read specialization for bool删除bool read专业化
  • Remove cv namespace删除cv命名空间
  • Move the read template inside namespace Dread模板移动到命名空间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 ._TpD::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 来考虑。

Demo演示

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM