部分类模板专业化是这个设计问题的答案吗?

App*_*ood 7 c++ oop templates specialization

假设您有一个班级,他们的工作就是连接到远程服务器.我想抽象这个类来提供两个版本,一个通过UDP连接,另一个通过TCP连接.我想构建最精简的运行时代码,而不是使用多态,我正在考虑模板.这是我想象的,但我不确定这是最好的方法:

class udp {};
class tcp {};

template<class T,typename X>
class service
{
private:
  // Make this private so this non specialized version can't be used
   service();
};

template<typename X>
class service<udp, X>
{
private:
   udp _udp;
   X _x;
};

template<typename X>
class service<tcp, X>
{
private:
   tcp _tcp;
   X _x;
};
Run Code Online (Sandbox Code Playgroud)

因此最终的好处是T的通用性仍然可用,但设置UDP或TCP连接所需的非常不同的代码已经过专门化.我想你可以将它们放在一个类中,或者提供另一个类,它遵循一些纯虚拟接口来设置网络连接,比如IConnectionManager.

但这确实留下了通用T的代码问题,现在必须在两个专用版本中编写和维护,它们最终都是相同的.如何最好地解决这个问题?我有一种感觉,我认为这一切都错了.

Joh*_*itb 12

最好使用传输协议的策略来完成此操作:

template<typename Transport>
class service : Transport {
public:
    typedef Transport transport_type;

    // common code
    void do_something() { 
        this->send(....);
    }
};

class tcp {
public:
    void send(....) {

    }
};

class udp {
public:
    void send(....) {

    }
};

typedef service<tcp> service_tcp;
typedef service<udp> service_udp;
Run Code Online (Sandbox Code Playgroud)

请注意,这也是多态的.它被称为编译时多态.将策略放入基类将受益于Empty-Base-Class-Optimization.也就是说,您的基类不需要占用任何空间.将策略作为成员具有另一个缺点,即您总是必须将内容委托给该成员,这可能会随着时间的推移而变得烦人." Modern C++ Design "一书深入描述了这种模式.

理想情况下,传输协议不需要知道有关它上面的协议的任何信息.但是如果由于某种原因你必须得到一些关于它的信息,你可以使用crtp模式wiki:

template<template<typename Service> class Transport>
class service : Transport<service> {

    // since we derive privately, make the transport layer a friend of us, 
    // so that it can cast its this pointer down to us. 
    friend class Transport<service>;

public:
    typedef Transport<service> transport_type;

    // common code
    void do_something() { 
        this->send(....);
    }
};

template<typename Service>
class tcp {
public:
    void send(....) {

    }
};

template<typename Service>
class udp {
public:
    void send(....) {

    }
};

typedef service<tcp> service_tcp;
typedef service<udp> service_udp;
Run Code Online (Sandbox Code Playgroud)

您不必将模板放入标题中.如果明确地实例化它们,您将获得更快的编译时间,因为必须包含更少的代码.把它放到service.cpp中:

template class service<tcp>;
template class service<udp>;
Run Code Online (Sandbox Code Playgroud)

现在,使用服务的代码不需要知道模板的服务代码,因为该代码已经生成到service.cpp的目标文件中.


Edo*_* A. 4

我会使用奇怪的重复模板模式,又名五点棕榈爆炸亚历山大技术:

template <typename Underlying>
class Transmit
{
public:
   void send(...)
   {
      _U.send(...)
   };

private:
    Underlying _U;
};

class Tcp
{
public:
   void send(...) {};
};

class Udp
{
public:
   void send(...) {};
};
Run Code Online (Sandbox Code Playgroud)

可能会有更多的模板参数和子类,但您明白了,您也可以使用静态方法。

顺便说一句,模板代码通常更高效,但也更大。