使用C++0x新特性为模板参数指定约束条件

在编写C++类模板时,有时希望模板参数满足某种要求,即约束条件,比如要求某个模板类型参数T必须派生于基类TBase。

在C#泛型中可以通过where关键字来指定约束条件,而C++模板则缺乏类似的约束机制。

C++0x中引入了一些新的特性,C++标准库也得到了改进和扩展,有两篇不错的参考文章:

Explicating the new C++ standard (C++0x), and its implementation in VC10

Standard C++ Library changes in Visual C++ 2010

利用这些新特性,可以为模板参数指定一些约束。

比如,WTL中的模板,其中的一些模板参数必须从指定类继承(直接或间接继承),才能编译通过,如CApplicationT类:

template<typename T, typename TMainWindow, bool bInitializeCom = false>

class CApplicationT :

    public CAppModule

{

public:

    //Call this method in the application's entry point[_tWinMain(...)]

    int WinMain(HINSTANCE hInstance,LPTSTR lpCmdLine,int nCmdShow)

    {

        //Ensure that TMainWindow is derived from CWindow

        static_assert(std::is_base_of<CWindow,TMainWindow>::value,

            "TMainWindow needs to be CWindow based.");

        UNREFERENCED_PARAMETER(lpCmdLine);

        T* pT = static_cast<T*>(this);

        //......

        int nRet = 0;

        {

            CMessageLoop msgLoop;

            AddMessageLoop(&msgLoop);

            TMainWindow wndMain;

            _g_hMainWindow = wndMain.Create(NULL,CWindow::rcDefault);

            if(_g_hMainWindow == NULL)

            {

                ATLTRACE(_T("Failed to create Main window!\n"));

                return 0;

            }

            wndMain.ShowWindow(nCmdShow);

            wndMain.UpdateWindow();

            wndMain.CenterWindow();

            //......

这个模板类有个类型参数TMainWindow,实现代码中调用了这个类的一些成员函数,如Create(…),ShowWindow()等等。然而,这些成员函数实际上是CWindow类的成员函数。也就是说,TMainWindow类必须从CWindow类继承(直接或间接继承),才能在模板实例化时正确编译通过。

否则,如果TMainWindow不是CWindow的派生类,在编译如下代码时:

CApplication<CTestWindow> g_MainApp;

编译器会提示如下错误:

e:\coding\mywtllib\wtlapp.h(56): error C2039: 'Create' : is not a member of 'CTestWindow'
d:\cpp\wtl\wtlapp\win7shell\mainapp.cpp(6) : see declaration of 'CTestWindow'

e:\coding\mywtllib\wtlapp.h(62): error C2039: 'ShowWindow' : is not a member of 'CTestWindow'
       d:\cpp\wtl\wtlapp\win7shell\mainapp.cpp(6) : see declaration of 'CTestWindow'

这种编译错误不够直观,当碰到某些不太常见的成员函数时,特别是使用别人编写的模板代码,又缺少文档说明时,很难搞清楚TMainWindow应当满足什么条件才能编译通过。

 

幸好,我们现在可以利用C++0x的一些新特性来显式指定TMainWindow必须从CWindow类继承(直接或间接继承),方法为在CApplicationT模板实现代码中添加一段静态断言代码:

template<typename T, typename TMainWindow, bool bInitializeCom = false>

class CApplicationT :

    public CAppModule

{

public:

    //Call this method in the application's entry point[_tWinMain(...)]

    int WinMain(HINSTANCE hInstance,LPTSTR lpCmdLine,int nCmdShow)

    {

        //Ensure that TMainWindow is derived from CWindow

        static_assert(std::is_base_of<CWindow,TMainWindow>::value,

            "TMainWindow needs to be CWindow based.");

        UNREFERENCED_PARAMETER(lpCmdLine);

        T* pT = static_cast<T*>(this);

        //......

这样,当TMainWindow不满足条件时,编译器就会提示如下错误:

e:\coding\mywtllib\wtlapp.h(25): error C2338: TMainWindow needs to be CWindow based.

这样,错误原因就清晰多了。

使用std::is_base_of<>时,需要添加头文件”#include <type_traits>”

你可能感兴趣的:(C++)