从C ++中的另一个模板方法调用模板方法?

时间:2014-08-25 20:30:18

标签: c++ templates

我目前遇到了模板化方法的问题。我有这个实现模板方法的公共类:

namespace Private { class InternalClass; }

namespace Public
{
    class PublicClass
    {
    public:
        PublicClass();
        virtual ~PublicClass();

        template<class T>
        bool Add(bool primary);

    private:
        Private::InternalClass* _pInternal;
    };

    template<class T>
    bool PublicClass::Add(bool primary) { return _pInternal->Add<T>(primary); }
}

内部类以这样的方式实现:

namespace Private
{
    class InternalClass
    {
    public:
        InternalClass();
        virtual ~InternalClass();

        template <class T>
        bool Add(bool primary);
    };

    template<class T>
    bool InternalClass::Add(bool primary) { return false; }
}

由于这个内部类头不能与提供的源一起使用,我必须在PublicClass头中转发它,然后在PublicClass.cpp文件中添加include到PrivateClass.h。

1)知道为什么我会收到以下错误:

  

错误:成员访问不完整类型'Private :: InternalClass'/ note:forward&gt;'Private :: InternalClass'的声明

2)隐藏我的PublicClass :: Add()实现的最佳方法是什么?

已更新

1)的错误原因是由于Cornstalks所说的this

对于2),如何在不在PublicClass头文件中包含PrivateClass.h的情况下隐藏我的实现?

1 个答案:

答案 0 :(得分:3)

您遇到了一个非常有趣的问题 - 您希望实现 PImpl idiom ,其中私有实现的类具有模板方法。好吧,这可以解决,这意味着您可以隐藏模板的实现,但只有当您知道将使用哪些类型来实例化您的程序中的Add<T>方法。

假设您的模板仅适用于AClassBClass类型。然后您可以按如下方式拆分文件(注释内联):

档案public.h

#ifndef PUBLIC_H
#define PUBLIC_H

// Forward declaration ! It's sufficient in this case !
namespace Private { class InternalClass; }

// Declare all classes your Add<T> method should work with
struct AClass {};
struct BClass {};

namespace Public
{
    class PublicClass
    {
    public:
        PublicClass() {}
        virtual ~PublicClass() {}

        template <typename T>
        bool Add(bool primary); // DO NOT implement this method, just declare

    private:
        Private::InternalClass* _pInternal;
    };

    // "Explicit instantiation declarations", for each type the method will work with:
    extern template bool PublicClass::Add<AClass>(bool primary);

    extern template bool PublicClass::Add<BClass>(bool primary);
}

#endif

档案public.cpp

#include "public.h"

// NOTE: this is hidden in CPP file, noone will see your implementation
namespace Private
{
    class InternalClass
    {
    public:
        InternalClass() {}
        virtual ~InternalClass() {}

        template <typename T>
        bool Add(bool primary);
    };

    // Magic! Here is the actual implementation of your private method
    template <typename T>
    bool InternalClass::Add(bool primary)
    {
        return false;
    }
}

namespace Public
{
    // Original definition moved to CPP file !
    template <typename T>
    bool PublicClass::Add(bool primary)
    {
        return _pInternal->Add<T>(primary);
    }

    // And again list the allowed types, this time using "explicit instantiation definitions"
    template bool PublicClass::Add<AClass>(bool primary);

    template bool PublicClass::Add<BClass>(bool primary);
}

档案main.cpp

#include "public.h"

int main()
{
    Public::PublicClass pc;
    pc.Add<AClass>(true); // works !
    pc.Add<BClass>(false); // works !

    // pc.Add<int>(true); linker error as expected,
    // becuase there is no explicit instantiation for Add<int>

    return 0;
}