使用指令VS在下使用声明交换++(using directive vs using declarat

2019-08-31 19:39发布

请参考下面的代码:

#include <algorithm>

namespace N
{

    template <typename T>
    class C
    {
    public:
        void SwapWith(C & c)
        {
            using namespace std; // (1)
            //using std::swap;   // (2)
            swap(a, c.a);
        }
    private:
        int a;
    };

    template <typename T>
    void swap(C<T> & c1, C<T> & c2)
    {
        c1.SwapWith(c2);
    }

}

namespace std
{

    template<typename T> void swap(N::C<T> & c1, N::C<T> & c2)
    {
        c1.SwapWith(c2);
    }

}

正如上面写的代码不会编译上的Visual Studio 2008/2010。 错误是:

'void N::swap(N::C<T> &,N::C<T> &)' : could not deduce template argument for 'N::C<T> &' from 'int'.

但是,如果我注释掉(1)并取消(2),它会编译OK。 是什么区别using namespace stdusing std::swap ,解释这种行为?

Answer 1:

第一种情况是用指令( using namespace X ),并且它的意思是,从命名空间中的名称X将可以定期查询,在第一公共命名空间X和电流范围。 在这种情况下,第一公共的命名空间的祖先::N::std:: ,所以使用指令会使std::swap仅当查找命中::

这里的问题是,查找启动时它会寻找里面的函数,那么类里面,那里面N ,它会找到::N::swap在那里。 由于检测到潜在的过载,定期查找没有继续在外命名空间:: 。 因为::N::swap是一个函数,编译器会做ADL(参数依赖查找),但该组相关联的命名空间为基本类型是空的,所以不会带来任何其他重载。 在这一点上查找完成,并重载启动。 它会尝试匹配与呼叫当前(单)过载和它将无法找到转化的方式int的说法::N::C ,你会得到错误。

在另一方面using声明( using std::swap )提供在当前上下文中的实体的声明(在这种情况下,函数本身的内部)。 查找就会发现std::swap立即停止定期查找与::std::swap ,并会使用它。



Answer 2:

最明显的原因是,using声明和using指令有不同的效果。 using声明立即介绍了名称到当前的范围,因此using std::swap介绍了名称到本地范围; 查找到此为止,你找到的唯一符号std::swap 。 此外,这发生在定义模板时,在空间中,因此后来的声明std都没有发现。 在下面的行中, swap将要考虑的是在所定义的一个<algorithm>那些由ADL(因此,一个命名空间中添加加N )。 (不过,这是真的用VC ++?编译器不正确执行名称查找,所以谁知道。)

A,使用指令指定的名称将出现“好像”他们在封闭两个指令和提名命名最近的命名空间中声明; 在你的情况下,全局命名空间。 而实际上它并不引入的名字; 它只是影响名称查找。 这在相关符号的情况下(或总是在VC ++的情况下)发生在调用点。

至于为什么你有这个特殊的错误消息:可能更多的与VC ++的一个问题,因为肯定在你的代码没有非deduceable上下文。 但是,没有任何理由期待两个变体是具有相同的行为,无论编译器。



Answer 3:

我已删除std下您的交换定义。 这是不是与此有关。 即使出它的代码都会有相同的问题。


这是由于查找之间差异的规则using directiveusing namespace std )和using declarationusing std::swap

微软表示,

如果一个局部变量具有相同的名称命名空间变量,命名空间变量是隐藏的。 这是具有相同的名称作为一个全局变量命名空间变量的错误。

#include<iostream>

namespace T {
    void flunk(int) { std::cout << "T";}
}

namespace V {
    void flunk(int) { std::cout << "V";}
}


int main() {
    using T::flunk;   // makes T::flunk local
    // using V::flunk;  // makes V::flunk local. This will be an error
    using namespace V;  // V::flunk will be hidden
    flunk(1);
}

根据这一点,由于你

template <typename T>
void swap(C<T> & c1, C<T> & c2)

std::swap当你使用会被隐藏

using namespace std; 

因此,只有在swap可用模板扣除N::swap ,它不会对工作, int ,因为它预计A S template class作为参数。

不是

using std::swap;

在这种情况下,它变成相当于本地定义 。 并且可以在没有问题地使用。



文章来源: using directive vs using declaration swap in C++