跟我学c++中级篇——变参模板的应用

一、说明

很多技术学会了是学会了,但是转眼就会忘记。这也是很多技术被束之高阁的主要原因,没有应用场景。当然,有了应用场景不用,那是另外一回事。那么,一个技术的产生一定是从实际的应用场景中来,但是传播的过程中,可能反而让很多人忘记了这个应用场景是什么。所以今天就聊聊这个变参模板到底怎么用,给出一些在实际场景中模拟的例子,让人一看就明白的那类。这样,有了同样类似的场景,就可以考虑把这个变参模板应用上去。
在前面的分析中可以看到,一个变参模板类一般分为三部分,第一部分是模板类的前置声明用来声明一个可变参数模板类;然后是一般的展开形式,也就是通过偏特化来实现部分可展开的模板类,最后就是反复提到的终止定义模板类来保证递归等的结束判断,这里一般是一个特化的类或者是一个全实例化的类。
在实际的应用中,就可以把这块专门编写模板封装起来,供外部调用。

二、应用

下面举出三个场景来应用变参模板:

1、实现工厂类
如果在实际场景中,需要一个工厂模式(可不要说从来没遇到过用工厂模式),这个工厂模式有不确定多个参数和类型需要传递,怎么办?传统的方式可以写很多个重载函数,或者写一个最长,然后每个都有默认参数,根据实际传入的参数来决定到底采用哪种方式来创建实例。但是这样做显得代码臃肿且不易维护和扩展。当然,也可以抽象一个类(接口),子类来继承,通过动态创建不同的类来实现,但这就需要维护者去编写这个继承类,这或多或少也会让开发者感到有些不好理解,特别是如果这个父类被封装到一个DLL库中,看不到实际的代码时,更是如此。那么变参模板就很容易实现:
先看一下如果不使用变参模板:

template
T* Instance()
{
    return new T();
}

template
T* Instance(T0 arg0)
{
    return new T(arg0);
}

template
T* Instance(T0 arg0, T1 arg1)
{
    return new T(arg0, arg1);
}
//..............
//当然后面还可以写更多个参数类型的
#include 

class Example0
{
public:
    Example0(int) 
    {
        std::cout << "class instance example0!" << std::endl;
    }
};

class Example1
{
public:
    Example1(int, double) 
    {
        std::cout << "class instance example1!" << std::endl;
    }
};
int main()
{
    Example0* pa = Instance(3);
    Example1* pb = Instance(3,2.0);
}

再看使用变参模板:

#include 
#include 
#include 

class Example0
{
public:
    Example0(int) 
    {
        std::cout << "class instance example0!" << std::endl;
    }
};

class Example1
{
public:
    Example1(int, double) 
    {
        std::cout << "class instance example1!" << std::endl;
    }
};
struct Example2
{
    Example2(int, double,std::string) 
    {
        std::cout << "struct instance example3!" << std::endl;
    }
};
template
std::shared_ptr Instance(Args&&... args)
{
    return std::make_shared(std::forward(args)...);
    //return std::shared_ptr(new T(std::forward(args)...));
}
void TestInstance()
{
    std::shared_ptr p0 = Instance(1);
    std::shared_ptr p1 = Instance(1, 2.0);
    std::shared_ptr p2 = Instance(1, 2,"Test");
}
int main()
{
    TestInstance();
    return 0;
}

这样写比上面简洁多了,这就是标准进步的结果。

2、实现类似代理委托
如果有c#或者Java开发经验的就会知道,其中的委托delegate非常好用。各种函数都可以轻易的转发调度。那么,在c++中用变参模板就可以近似实现类似的功能,而且比之更灵活,看下面的例子:

template 
class  CppDelegate
{
public:
    CppDelegate(T* t, R(T::* func)(Args...)) :t_(t), func_(func) {}

    R operator()(Args&&... args)
    {
        return (t_->*func_)(std::forward(args) ...);
    }

private:
    T * t_;
    R(T::* func_)(Args...);//万能函数
};

template 
CppDelegate CreateDelegate(T* t, R(T::* f)(Args...))
{
    return CppDelegate(t, f);
}

class DgEx
{
public:
    void MyFunc0(int d) { std::cout << d << std::endl; }
    void MyFunc1(int d, std::string s) { std::cout << s << d << std::endl; }
    int MyFunc2(std::string s,int d) { std::cout << s << std::endl; return d; }
};

void TestDelegate()
{
    DgEx de;
    auto d0 = CreateDelegate(&de, &DgEx::MyFunc0);
    d0(16);
    auto d1 = CreateDelegate(&de, &DgEx::MyFunc1);
    d1(6, "display:");
    auto d2 = CreateDelegate(&de, &DgEx::MyFunc2);
    int r = d2("this is test!",3);
    std::cout << "return value is:" << r << std::endl;
}
void TestDelegate();

int main()
{
    TestDelegate();
    return 0;
}

这里面有一个万能函数,不知道还记不记得“C++变参函数实现三步曲之三C++11变参模板模式”文中就提到了这种方式。不过这个还是比较功能单一,大家可以在这个基础上进行扩展。

3、std::bind的变参绑定
这个在前面提到的文章中也有过描述,看一个例子:

#include 
#include 
#include 

class MyBind
{
public:
    template
    void Call(T&... args)
    {
        {
            func_ = std::bind(&MyBind::Test, this, args...);
            std::cout << "test bind args..." << std::endl;
            func_();
        }
    }

    template
    void Test(T&... args)
    {
        std::cout << "call Test " << std::endl;
    }

    std::function func_;

};

int  TestMyBind()
{
    int a = 6;
    double b = 3.9;
    std::string c{ "test bind" };

    MyBind myBind;
    myBind.Call(a, b, c);

    return 0;
}

都是需要认真看才能搞清楚,所以看这些例子,还是要仔细静下心来,弄明白了,就真的掌握了。不要看看会,就觉得会了,自己写一个试试,可能会有意外的惊喜。
这三个例子,都是比较好的应用场景,在这些简单的例子的入门引导下,就可以不断的在实际的应用中完善修改,最终形成一个符合自己工程应用的模块,最合适的才是最好的。

三、总结

学以致用,这句话说起来容易,可做起来真难啊。如果不能深刻的理解一门技术,就无法自如的应用他,而只能照猫画虎的外向型模仿。不过,这种外向型模仿却又是深刻理解的前提和基础。学习本身就是一个由表及里,由外到内的过程。越是学习应用的多,对一门技术的理解就会越发的深刻。而反过来,应用这门技术就会越发的灵活自如。
计算机技术就是如此,多读书,勤实践,不断的从理论到实践并不断的反馈自己对理论的理解,如此往复,其期可待。

你可能感兴趣的:(C++11,C++,c++,开发语言)