【问题标题】:Forward declaring a hidden typedef in C++在 C++ 中前向声明隐藏的 typedef
【发布时间】:2018-08-13 10:26:38
【问题描述】:

我有一个命名空间N0,它有包括N1 在内的子命名空间。调用代码只知道外部命名空间。我想在外部命名空间中编写一个函数,该函数返回一个std::unique_ptr<N1::T>,该结果在N0 的其他地方使用。但是,调用者不应该知道N1。我想做的是:

// N0.h
namespace N0 {
    typename T; // This isn't real C++.
    std::unique_ptr<T> foo();
    void bar(std::unique_ptr<T>&&);
}
// N0.cpp
#include "N1.h" // Get N1::T
namespace N0 {
    typedef N1::T T;
    ...
}

也就是说,我想公开一个调用者看不到的类型,但在内部我想实际使用不同命名空间中的类型。这样,其他人可以直接声明namespace N0 { class T; },而不必知道T实际上在N1中。

我可以将T 本身移动到N0,但它确实属于N1

我可以用N0 中的虚拟类包装T,但这很丑,指针基本上应该这样做。

我可能会创建一个 N0::T 的子类 N1::T,但这似乎也很恶心。

N0 有没有办法转发声明“我有一个类型,而你不需要知道它是什么”并且该类型实际上位于不同的命名空间中?换句话说:为什么class C; class C{}; 合法而class C; typedef int C; 是非法的? (同样class C; using C = int;typedef C; typedef int C;。)它们在我看来基本相同,我想不出一个巧妙的模板技巧来解决它。我能想到的唯一区别是 typedef 版本不受 Koenig 查找的影响。

【问题讨论】:

  • 我不这么认为。我只是希望N0 能够公开说“我有一个类型T”,你可以有指针,然后私下让N0 将其定义为“实际上当我说T 我的意思是N1::T .
  • 继承可能是一个选项stackoverflow.com/a/44136249/597607

标签: c++ namespaces forward-declaration


【解决方案1】:

我的意思是你可以这样做:

// N0.h
namespace N0 {
    std::unique_ptr<T> foo();
    void bar(std::unique_ptr<T>&&);
}
// N0.cpp
namespace N0 {
    typedef N1::T t;
}

#include "N0.h"

namespace N0 {
    // whatever...
}

【讨论】:

  • 我不关注。 TN0.h 中来自哪里?
  • @Ben 不知从何而来。好吧,这里的技巧是在 已经定义了N0::T 之后将其包含在内,以便标头中的代码有效。它基本上是 like this,其中中间的命名空间是你的标题中的内容。
  • 但是foo() 的调用者呢?他们会#include "N0.h" 并得到`未声明的标识符'T'`对吗?
  • @Ben Jup 如果不指定要使用哪个T,并且只能用于单个T
【解决方案2】:

在您描述的情况下, foo 应该作为模板函数实现:

namespace N0 {
    template <typename T>
    std::unique_ptr<T> foo(){...};

    template <typename T>
    void bar(std::unique_ptr<T>&&){...};
}

你应该使用包装/重载函数来完成最后的技巧:

namespace N0 {
std::unique_ptr<N1::T> foo() { return foo<N1::T>(); }
//for bar there is no need to wrap, cause the T could be resolved by parameters.
}

【讨论】:

    【解决方案3】:

    这是我想出的最好的方法,它似乎有效。我仍然觉得应该有一种方法可以不使用“技巧”使N1::T 对呼叫者完全隐藏:

    // N0.h
    #pragma once
    #include <memory>
    
    namespace N0 {
        struct OpaqueObject { virtual ~OpaqueObject() {} };
        std::unique_ptr<OpaqueObject> foo();
        void bar(std::unique_ptr<OpaqueObject>&&);
    }
    
    //N0.cpp
    #include "N1.h"
    
    namespace N0 {
       std::unique_ptr<OpaqueObject> foo() { return std::unique_ptr<N1::T>(new N1::T()); }
       void bar(std::unique_ptr<OpaqueObject> &&) {}
    }
    
    // N1.h
    #pragma once
    #include "N0.h"
    
    namespace N1 {
      class T : public N0::OpaqueObject {};
    }
    
    // test.cpp
    #include "N0.h"
    
    int main() {
      auto x = N0::foo();
      N0::bar(std::move(x));
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-22
      • 1970-01-01
      • 2013-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-19
      • 2023-03-12
      • 1970-01-01
      相关资源
      最近更新 更多