键入别名和不完整类型

时间:2013-07-23 01:47:35

标签: c++ templates c++11 traits

我可能已经到达这里解决什么应该是一个简单的问题。我在这里开始这个问题: Getting type of base class at compile time

基本上我正在尝试让类管理它自己的指针类型。我正在包装一个C库,其中一些结构嵌入了引用计数,而其他结构则没有。那些没有的,我想使用shared_ptr。那些做的,我想使用intrusive_ptr。我想避免依赖程序员的智力来确保使用正确的包装器。最后,我想添加更多依赖于此行为的功能,但我还没有。

@Yakk使用模板类型别名提出了一个有趣的解决方案,我试图实现它。不幸的是,我已经把自己放在了一个我似乎无法解决循环引用编译器满意度的地方。我得到一个“嵌套名称说明符中命名的不完整类型'Test2'”指向“using pointer =”行的错误。对于我对Test :: f()的定义,我也得到了一个奇怪的“定义与返回类型的声明不同”,但我怀疑一旦我解决了第一个错误,它可能会自行解决。

我在此错误类型中找到的大多数引用都涉及头文件的排序,但即使将所有内容放在一个文件中,我也无法弄清楚如何排序以使此问题消失。

有什么想法吗?

#include <iostream>
#include <memory>


template<typename T>
class Pointered: public std::enable_shared_from_this<T>
{
public:
    using pointer=std::shared_ptr<T>;     //<-- incomplete type named error
    using weakPointer = std::weak_ptr<T>;
};


template<typename T>
using Ptr =  typename T:: pointer;

template<typename T>
using WkPtr = typename T:: weakPointer;


class Test2;

class Test:public Pointered<Test>
{
public:
    Ptr<Test2> f();
};


class Test2:public Pointered<Test2>
{
public:
    Ptr<Test> p;
    Test2(Ptr<Test> ptr):p(ptr){}
};


int main(int argc, const char * argv[])
{
    Ptr<Test> p=std::make_shared<Test>();
    Ptr<Test> p3=p;
    p->f();
    std::cout << "Refcount: " << p.use_count() << std::endl;
}


//definition differs from declaration in return type error here
Ptr<Test2> Test::f()
{
    return Ptr<Test2>(new Test2((Ptr<Test>)shared_from_this()));
}

1 个答案:

答案 0 :(得分:4)

您不能转发声明嵌套类型,因为您需要定义封闭类型,但在您的情况下,您有一个循环依赖关系禁止它。

首先要考虑的是循环依赖是否真的是一个好主意。在大多数情况下,循环依赖性被认为是代码气味(表明设计存在问题)。如果你可以删除循环依赖,那么一切都会变得更容易。

另一种选择是将嵌套类型的依赖关系移动到类型特征,可以在外部定义类型特征之前定义:

template <typename T>
struct pointer_traits;

template <>
struct pointer_traits<Test1> {
   typedef std::shared_ptr<Test1> ptr;
   typedef std::shared_ptr<Test1> wptr;
};

通过将依赖项移到实际类型之外,您不再具有循环依赖性(在语法级别,您仍应重新访问设计)。然后,您可以根据需要添加语法糖:

template <typename T>
using ptr = typename pointer_traits<T>::ptr;

class Test1 {
    ptr<Test2> p2;
};

如果你真的希望这些类型也是嵌套的,你可以使用继承将它们带入范围,或者以更简单的方式添加相应的typedef:

class Test1 {
    typedef ptr<Test1> ptr_t;
// ...

请注意,这是一个粗略的近似值,如果您选择这种方法,您可以通过添加更多的语法糖来对特征的细节和使其更甜的类型进行一些处理,例如,您可以为shared_ptr_traitsintrusive_ptr_traits提供两个特征,并提供一个单行特征来确定您要从哪个中提取typedef,从而将特征(每种类型)的定义减少为单个线。