在C ++中声明隐藏的typedef

时间:2018-03-05 17:17:06

标签: c++ namespaces forward-declaration

我有一个命名空间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

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

我可能会创建一个类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查询的影响。

3 个答案:

答案 0 :(得分:0)

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

// 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...
}

答案 1 :(得分:0)

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

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

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

你应该使用wrap / overload函数来做最后的技巧:

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.
}

答案 2 :(得分:0)

这是我提出的最好的,这似乎有效。我仍然觉得应该有办法不使用“技巧”使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));
}