代码片段不能在 C++17 下编译,命名空间问题?

Code snippet doesnot compile under C++17, namespace issue?

#include <iostream>
#include <vector>

namespace Cactus
{
    namespace Json
    {
        class Value
        {
        public:
            Value(){}

        };

    }

    typedef std::vector< int >      vectorInt;

    inline Cactus::Json::Value& operator << (Cactus::Json::Value& os, const vectorInt& v)
    {
        return os;
    }
    inline Cactus::Json::Value& operator >> (Cactus::Json::Value& is, vectorInt& v)
    {
        return is;
    }
}

namespace App
//namespace Cactus
{

    void f()
    {
        Cactus::vectorInt ints;
        Cactus::Json::Value val;

        val << ints;
    }
}

int main()
{
    App::f();
}

遇到错误,

main.cpp: In function 'void App::f()':
main.cpp:38:13: error: no match for 'operator<<' (operand types are 'Cactus::Json::Value' and 'Cactus::vectorInt' {aka 'std::vector<int>'})
   38 |         val << ints;
      |         ~~~ ^~ ~~~~
      |         |      |
      |         |      Cactus::vectorInt {aka std::vector<int>}
      |         Cactus::Json::Value

但是如果使用“命名空间仙人掌”,它会编译。但是我必须使用“namespace App”,有什么建议吗?

更新:问题已解决。 将两个运算符移动到全局命名空间有效。 或者添加使用 Cactus 也可以。

那些运算符重载必须在您的 f 函数所在的范围内。当函数 fCactus 命名空间中时,这些运算符重载在范围内。但是当它在命名空间 App 下时,那些就超出了范围。因此,要么将这些运算符重载放在全局命名空间中,要么将运算符重载放在与 class Value 相同的命名空间中,或者将使用该运算符的所有函数放在相同的命名空间中。另一种方法是在函数内部使用 using 语句,使用它们将它们导入到该函数的全局范围。

它被称为ADL。至少,在您的示例中,函数 Cactus::Json::Value& operator << (Cactus::Json::Value& os, const vectorInt& v) 无法在参数类型 val 的关联 classes 或名称空间中找到。因为 ADL 应受以下规则约束:

For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes are determined entirely by the types of the function arguments (and the namespace of any template template argument). Typedef names and using-declarations used to specify the types do not contribute to this set. The sets of namespaces and classes are determined in the following way:

If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the innermost enclosing namespaces of its associated classes. [...]

If an associated namespace is an inline namespace, its enclosing namespace is also included in the set. If an associated namespace directly contains inline namespaces, those inline namespaces are also included in the set.

因此,class Value 的最内层封闭命名空间是 Json。在 Value 的范围内没有这样的可用函数,命名空间 Json 也类似,因此你遇到了那个错误。


如何解决?

  1. 将您提供的所有函数移动到命名空间 Json
  2. namespace Json修改为inline namespace Json

拿一个就好了