Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 递归模板习惯用法如何避免基类是子类的朋友_C++_Templates_Design Patterns_Idioms_Crtp - Fatal编程技术网

C++ 递归模板习惯用法如何避免基类是子类的朋友

C++ 递归模板习惯用法如何避免基类是子类的朋友,c++,templates,design-patterns,idioms,crtp,C++,Templates,Design Patterns,Idioms,Crtp,我使用自动注册工厂中基类的所有子类。然而在我的设计中,子类必须有一个作为友元类的基类。因为我的基类的构造函数应该是私有的,以避免通过工厂以外的方式实例化这个类 总体目标是工厂的注册在BaseSolver中完成,子类只能通过工厂进行实例化 下面是我的基类的代码,它自动在SolverFactory中注册所有子类 template<class T> struct BaseSolver: AbstractSolver { protected: BaseSolver() {

我使用自动注册工厂中基类的所有子类。然而在我的设计中,子类必须有一个作为友元类的基类。因为我的基类的构造函数应该是私有的,以避免通过工厂以外的方式实例化这个类

总体目标是工厂的注册在BaseSolver中完成,子类只能通过工厂进行实例化

下面是我的基类的代码,它自动在SolverFactory中注册所有子类

template<class T>
struct BaseSolver: AbstractSolver
{
protected:
    BaseSolver()
    {
        reg=reg;//force specialization
    }
    virtual ~BaseSolver(){}
    /**
     * create Static constructor.
     */
    static AbstractSolver* create()
    {
        return new T;
    }

    static bool reg;
    /**
     * init Registers the class in the Solver Factory
     */
    static bool init()
    {
        SolverFactory::instance().registerType(T::name, BaseSolver::create);
        return true;
    }
};

template<class T>
bool BaseSolver<T>::reg = BaseSolver<T>::init();
模板
结构BaseSolver:AbstractSolver
{
受保护的:
BaseSolver()
{
reg=reg;//强制专门化
}
虚拟~BaseSolver(){}
/**
*创建静态构造函数。
*/
静态AbstractSolver*创建()
{
返回新的T;
}
静态布尔寄存器;
/**
*init在解算器工厂中注册该类
*/
静态bool init()
{
SolverFactory::instance().registerType(T::name,BaseSolver::create);
返回true;
}
};
模板
bool BaseSolver::reg=BaseSolver::init();
这里是我的子类的头文件:

class SolverD2Q5 : public BaseSolver<SolverD2Q5>{

private:
  //how can I avoid this?
  friend class BaseSolver;

  SolverD2Q5();

  static const std::string name;

}
class SolverD2Q5:公共BaseSolver{
私人:
//我怎样才能避免这种情况?
好友类基址求解器;
SolverD2Q5();
静态常量std::字符串名称;
}
这个很好用。然而,我真的不想将BaseSolver添加为好友类,但是我不希望构造函数和静态成员名是公共的

有没有更优雅的解决方案或更好的布局来避免这种情况?

更新: 我相信这个技巧还没有被理解,因此我现在就创建了完整的解决方案。这只是对OP的代码的一个小更改。只需将
BaseSolver
中的T替换为从
T
派生的空类定义即可

原文: 我认为可以通过将友谊委托给一个封装类来实现,这个封装类是基解算器的私有类。该类将从要为其创建实例的任何类继承。编译器应该优化包装器类

#include <iostream>
#include <map>

struct AbstractSolver { virtual double solve() = 0; };

class SolverFactory
{
    std::map<char const * const, AbstractSolver * (*)()> creators;
    std::map<char const * const, AbstractSolver *> solvers;
public:
    static SolverFactory & instance()
    {
        static SolverFactory x;
        return x;
    }
    void registerType(char const * const name, AbstractSolver *(*create)())
    {
        creators[name] = create;
    }
    AbstractSolver * getSolver(char const * const name)
    {
        auto x = solvers.find(name);
        if (x == solvers.end())
        {
            auto solver = creators[name]();
            solvers[name] = solver;
            return solver;
        }
        else
        {
            return x->second;
        }
    }
};

template<class T> class BaseSolver : public AbstractSolver
{
    struct Wrapper : public T { // This wrapper makes the difference
        static char const * const get_name() { return T::name; }
    };
protected:
    static bool reg;
    BaseSolver() {
        reg = reg;
    }
    virtual ~BaseSolver() {}
    static T * create() {
        return new Wrapper; // Instantiating wrapper instead of T
    }
    static bool init()
    {
        SolverFactory::instance().registerType(Wrapper::get_name(), (AbstractSolver * (*)())BaseSolver::create);
        return true;
    }
};

template<class T>
bool BaseSolver<T>::reg = BaseSolver<T>::init();

struct SolverD2Q5 : public BaseSolver<SolverD2Q5>
{
public:   
    double solve() { return 1.1; }
protected: 
    SolverD2Q5() {} // replaced private with protected
    static char const * const name;
};
char const * const SolverD2Q5::name = "SolverD2Q5";

struct SolverX : public BaseSolver<SolverX>
{
public:    
    double solve() { return 2.2; }
protected: 
    SolverX() {} // replaced private with protected
    static char const * const name;
};
char const * const SolverX::name = "SolverX";

int main()
{
    std::cout << SolverFactory::instance().getSolver("SolverD2Q5")->solve() << std::endl;
    std::cout << SolverFactory::instance().getSolver("SolverX")->solve() << std::endl;
    std::cout << SolverFactory::instance().getSolver("SolverD2Q5")->solve() << std::endl;
    std::cout << SolverFactory::instance().getSolver("SolverX")->solve() << std::endl;

    char x;
    std::cin >> x;
    return 0;
}
#包括
#包括
结构抽象解算器{virtual double solve()=0;};
类求解工厂
{
地图创作者;
地图解算器;
公众:
静态SolverFactory和实例()
{
静态溶剂工厂x;
返回x;
}
void registerType(char const*const name,AbstractSolver*(*创建)()
{
创建者[名称]=创建;
}
AbstractSolver*getSolver(字符常量*常量名称)
{
自动x=解算器。查找(名称);
if(x==solvers.end())
{
自动解算器=创建者[名称]();
解算器[名称]=解算器;
返回解算器;
}
其他的
{
返回x->秒;
}
}
};
模板类BaseSolver:PublicAbstractSolver
{
结构包装器:public T{//此包装器起作用
静态字符常量*常量get_name(){return T::name;}
};
受保护的:
静态布尔寄存器;
BaseSolver(){
reg=reg;
}
虚拟~BaseSolver(){}
静态T*create(){
返回新包装器;//实例化包装器而不是T
}
静态bool init()
{
SolverFactory::instance().registerType(包装器::get_name(),(AbstractSolver*(*)())BaseSolver::create);
返回true;
}
};
模板
bool BaseSolver::reg=BaseSolver::init();
结构SolverD2Q5:公共BaseSolver
{
公众:
double solve(){return 1.1;}
受保护的:
SolverD2Q5(){}//已将private替换为protected
静态字符常量*常量名称;
};
char const*const SolverD2Q5::name=“SolverD2Q5”;
struct SolverX:公共BaseSolver
{
公众:
double solve(){return 2.2;}
受保护的:
SolverX(){}//将private替换为protected
静态字符常量*常量名称;
};
char const*const SolverX::name=“SolverX”;
int main()
{

std::cout solve()为什么BaseSolver需要是一个friend类?您可以将
friend类T
添加到BaseSolver吗?这会有什么帮助?我不想访问BaseSolver中的私有方法,但BaseSolver应该访问解算器的私有成员。我喜欢这样的设计。为什么
friend
声明是一个问题?Replaci在
SolverD2Q5
中使用
protected
的ng
private
解决了这个问题。我之前的回答只是给出了一个提示。现在我已经添加了一个完整的示例。我看不出这不是一个解决方案,因此我认为s甚至不具有侵入性,而且它不会在可执行文件中创建额外的代码。