C++ 命名空间中的模板专门化

C++ 命名空间中的模板专门化,c++,templates,namespaces,template-specialization,C++,Templates,Namespaces,Template Specialization,发生这种奇怪的行为时,我正在处理一些代码: 在第一个测试中,基本模板化函数、用户和模板化专门化位于同一命名空间中,其行为与我预期的一样: namespace Test1 { template <typename V, typename T> int doFoo(V& a_visitor, T& a_value) { return 0; } stru

发生这种奇怪的行为时,我正在处理一些代码:

在第一个测试中,基本模板化函数、用户和模板化专门化位于同一命名空间中,其行为与我预期的一样:

    namespace Test1
    {
        template <typename V, typename T>
        int doFoo(V& a_visitor, T& a_value)
        {
            return 0;
        }

        struct Foo
        {
            template <typename T>
            int process(T const& a_value)
            {
                return doFoo(*this, a_value);
            }
        };

        template <typename T>
        int doFoo(Foo& a_vis, T const& a_ptr)
        {
            return 1;
        }
    }

    int main()
    {
        int const k{ 42 };

        return Test1::Foo{}.process(k); // returns 1
    }

namespace Test1
{
模板
int doFoo(V&a_访客、T&a_值)
{
返回0;
}
结构Foo
{
模板
整数过程(T常数和a_值)
{
返回doFoo(*这是一个_值);
}
};
模板
int doFoo(Foo&a_vis,T const&a_ptr)
{
返回1;
}
}
int main()
{
int常量k{42};
返回Test1::Foo{}.process(k);//返回1
}
但当我在另一个命名空间中移动基模板函数及其专用化时,会选择基模板函数:

namespace Test2
{
    namespace b
    {
        template <typename V, typename T>
        int doBar(V& a_visitor, T& a_value)
        {
            return 0;
        }
    }

    struct Bar
    {
        template <typename T>
        int process(T const& a_value)
        {
            return b::doBar(*this, a_value);
        }
    };

    namespace b
    {
        template <typename T>
        int doBar(Bar& a_vis, T const& a_ptr)
        {
            return 1;
        }
    }
}

int main()
{
    int const k{ 17 };

    return Test2::Bar{}.process(k); // returns 0
}
namespace Test2
{
命名空间b
{
模板
int doBar(V&a_访客、T&a_值)
{
返回0;
}
}
结构条
{
模板
整数过程(T常数和a_值)
{
返回b::doBar(*这个,a_值);
}
};
命名空间b
{
模板
内部多巴(巴-阿-维斯、T-康斯特和阿-普特)
{
返回1;
}
}
}
int main()
{
int常量k{17};
返回Test2::Bar{}.process(k);//返回0
}
EDIT我甚至可以做更奇怪的事情:在示例1中,如果我用
Test1::doFoo
替换对
doFoo
的调用,我又会得到错误的行为


谁能解释一下这里发生了什么事?如果我真的需要struct Bar不在命名空间b中,该怎么办?

首先,这些不是专门化,而是重载。完全不同的函数模板彼此不相关

您看到的行为与您的行为一致。当遇到非限定的函数调用时,编译器通过检查与函数调用的每个参数相关联的名称空间来构建重载集

通常情况下,这不会找到“之后”的声明,但模板是特殊的。在模板中,依赖名称的查找(例如依赖于模板参数的函数调用)(
a_值的类型
)在模板实例化后执行,而不是在定义点执行。这发生在
main
中,在名称空间完成并且所有重载都可用之后,因此ADL会找到第二个重载


这也是为什么当您通过
Test1
限定调用时,您不再发现第二个重载。这否定了ADL,只允许在调用点之前出现重载。解决此问题的最简单方法可能是延迟
进程的定义
,直到所有重载可用为止,正如其他答案所示。

谢谢!我认为ADL是这里的关键。也就是说,在您的第三段之后,我有点困惑:Test2中的进程仍然是模板化的,因此它不应该找到重载,因为实例化点仍然在oberload声明之后吗?ps:我在第4段中迷路了,不确定你是否在引用我的编辑。@VictorRouin-ADL仍然发生,但与
条码相关联的命名空间中没有
doBar
b
未关联)。所以ADL不会向集合中添加任何重载。。好的,我想我明白了。ADL+模板用户的组合使之成为可能。好吧,我想我会放弃我的一个名称空间;)