如何使用嵌套命名空间来避免歧义?

How to use nested namespace to avoid ambiguity?

我在相应的命名空间中定义了以下运算符:

namespace literals
{

constexpr ID operator"" _ID(const unsigned long long dyngateID)
{
    // ...
    // return a constructed id
}

namespace multiplied
{

constexpr ID operator"" _ID(const unsigned long long dyngateID)
{
    // ...
    // return an id constructed in a specific way
}

} // namespace multiplied
} // namespace literals

在 .cpp 文件中,我想同时使用这两个函数,因此我声明了 using namespace literals,当我在具体函数中声明 using namespace multiplied 时,我得到了 ambiguous call to overloaded function编译错误。如何区分这些功能?

Test.cpp

using namespace literals;

void f()
{
    // here I am using literals' _ID which is fine
    const Type id{1_ID};
}
void g()
{
    // here I want to use multiplied's _ID, but obviously I am failing to do so
    using namespace multiplied;
    const Type id{1_ID};
}

考虑以下代码:

#include <iostream>

namespace one
{
    int func(int num1, int num2)
    {
        return num1 * num2;
    }

    namespace two
    {
        int func(int num1, int num2)
        {
            return num1 * num2;
        }
    }
}

int f()
{
    return one::two(1, 2) + 10;
}
int g()
{
    return one::two::func(3, 4) + 10;
}

int main()
{
    std::cout << f() << std::endl; 
    std::cout << g() << std::endl;
}

以上代码将编译并且 运行 非常好,并且将按预期工作,f() 使用 one::func()g() 使用 one::two::func()。如果你必须写 `using namespace one;'那么你可以这样做:

using namespace one;

int f()
{
    return func(1, 2) + 10;
}
int g()
{
    return two::func(3, 4) + 10;
}

这也会产生相同的输出。

using namespace 的名称查找规则使得它引入的声明似乎位于包含当前命名空间范围和目标命名空间范围的 inner-most 命名空间范围内。

因此,基于多个可达 using namespace 语句的范围来消除歧义是没有好处的。

相反,您可以使用 using 声明导入声明:

void g()
{
    using multiplied::operator""_ID;
    const Type id{1_ID};
}

这将表现得好像运算符是在范围内声明的,因此名称查找将停在那里,不会查看外部 using namespace.

导入的声明

或者,您可以通过限定调用直接调用 user-defined 文字运算符:

void g()
{
    const Type id{multiplied::operator""_ID(1)};
}

作为另一种可能性,您始终可以限制 using namespace 语句的范围,以便使用运算符从任何给定范围只能访问 using namespace literals;using namespace literals::multiplied; 中的一个,例如:

// no using namespace at this scope

void f()
{
    using namespace literals;
    const Type id{1_ID};
}
void g()
{
    using namespace literals::multiplied;
    const Type id{1_ID};
}