首页 > 解决方案 > C++ 奇怪的模板/命名空间行为

问题描述

我在编译代码时遇到问题,因为它无法在模板上找到匹配的函数。我已将问题缩小到此示例:

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[]) { }

在 Gcc 9.10 上,我收到以下错误:

invalid initialization of reference of type 'bool&' from expression of type 'D::A'  { read(n, value, _Tp()); }

在 Visual Studio 2019 上:

Error   C2664    'void cv::read(const cv::FileNode &,bool &,bool)': cannot convert argument 2 from '_Tp' to 'bool &'

我发现以下任何更改都会使代码编译:

不幸的是,以前的修复都不适用于我原来的问题,我仍然没有真正理解为什么它无法找到read模板。

标签: c++templatesnamespacesargument-dependent-lookup

解决方案


ADL 反击:

template<typename _Tp> static inline void operator >> (const FileNode& n, _Tp& value)
{
    read(n, value, _Tp());
}

read未声明,因此只能通过ADL找到

因此它将在与FileNode(so cv) 关联的名称空间中搜索,以及与_Tp.

什么时候,它将是命名_Tp空间。D::AD

唯一可能的重载readcv::readwhich take bool

read<T>上面的移动声明cv::operator >>解决了这个问题,ADL 也可以考虑。

演示


推荐阅读