說(shuō)明:
要看懂后面那部分代碼,即使用Typelist的部分,最好預(yù)先看過(guò)《C++設(shè)計(jì)新思維》,英文版名為《Modern C++ Design》。
If模板類(lèi)在寫(xiě)完后想起來(lái)好像在哪見(jiàn)過(guò),早晨去公司查閱了一下,在《產(chǎn)生式編程——方法、工具與應(yīng)用》一書(shū)中有講,英文名為《Generative Programming -- Methods, Tools, and Applications》基本和本篇中一個(gè)樣。
前2篇亂七八糟地講了一些,有一個(gè)遺留問(wèn)題,函數(shù)原型的推導(dǎo)。
簡(jiǎn)要描述如下:
Method < void(in<int>, in<char>, inout<string>, out<short>) > method;
// 同步調(diào)用
string str = "hello";
short value = 2;
method (3, 'a', str, value);
// 異步調(diào)用1
method.async_call (3, 'a', "hello");
// 異步調(diào)用2
void test_func (int, char, string, short);
method.async_call (3, 'a', "hello", test_func);
要產(chǎn)生這3種函數(shù)形式。參數(shù)類(lèi)型如何轉(zhuǎn)換,是以后的話(huà)題,本篇主要解決異步調(diào)用的函數(shù)原形推導(dǎo)問(wèn)題。本篇也不討論Method的模板參數(shù)(即那個(gè)函數(shù)類(lèi)型)返回類(lèi)型不為void的情況。
第一種形式,同步調(diào)用,比較好處理,參數(shù)個(gè)數(shù)和模板參數(shù)的數(shù)量相同。
后2種形式,如何讓編譯器根據(jù)in/out來(lái)推導(dǎo)出函數(shù)原型?
我們需要編譯器做這樣的處理,async_call的參數(shù)類(lèi)型中,in類(lèi)型的參數(shù)將保留,out類(lèi)型的參數(shù)不需要,inout類(lèi)型也需要保留。
要用到的Loki頭文件:
#include <static_check.h>
#include <Typelist.h>
using namespace Loki;
using namespace Loki::TL;
首先看看in/inout/out的聲明。為了簡(jiǎn)化,這里去掉了跟類(lèi)型推導(dǎo)無(wú)關(guān)的部分。
class NullType
{
NullType ();
};
template <class T>
struct in
{
typedef T OriginalType;
};
template <class T>
struct out
{
typedef T OriginalType;
};
template <class T>
struct inout
{
typedef T OriginalType;
};
下面Method模板類(lèi)的聲明,使用偏特化來(lái)產(chǎn)生代碼。為了簡(jiǎn)化,我只取函數(shù)參數(shù)個(gè)數(shù)為4個(gè)參數(shù)的版本,比照著上面的代碼來(lái)解釋?zhuān)唤忉宮ethod.async_call (3, 'a', "hello", test_func);這個(gè)版本,因?yàn)榱硪粋€(gè)比它簡(jiǎn)單。
template <class T>
struct Method
{
};
template <class Ret, class A, class B, class C, class D>
struct Method <Ret(A,B,C,D)>
{
};
根據(jù)上面Method的定義,Method < void(in, in, inout, out) > ,async_call函數(shù)的類(lèi)型將是:
typedef void (*FUNC_TYPE)(int, char, string, short);
void async_call (int, char, string, FUNC_TYPE func);
實(shí)際上FUNC_TYPE應(yīng)該能夠接受更廣泛的類(lèi)型,比如void(int, char, char*, short),這可以在內(nèi)部做一些轉(zhuǎn)換,不過(guò)本篇的重點(diǎn)不在這里,所以只講上面的那種形式。
直接在Method類(lèi)中實(shí)現(xiàn)有些麻煩,所以我把這個(gè)函數(shù)放在一個(gè)基類(lèi)中實(shí)現(xiàn),只要編譯器能幫我們推導(dǎo)出下面這種形式就行了:
template <class Ret, class A, class B, class C, class D>
struct Method <Ret(A,B,C,D)> : public Base < A, B, C >
{
};
注意,這里是以Method < void(in, in, inout, out) >這種形式來(lái)講的,才會(huì)有上面那種繼承關(guān)系。而實(shí)際上,由于in/out在參數(shù)中的位置、數(shù)量都是未知的,要到定義時(shí)才能確定,所以使用模板來(lái)推導(dǎo)。(入正題了)
也就是說(shuō),只要我們能使用靜態(tài)推導(dǎo)方式,獲得A,B,C,D這四個(gè)參數(shù)中所有的in類(lèi)型,把它交給Base作為模板參數(shù)就成了。
這里需要一個(gè)輔助的模板類(lèi),用來(lái)在編譯時(shí)幫助推導(dǎo):
template <class T>
class InOutTypeTraits
{
Loki::CompileTimeError <false> Not_Supported_Type;
};
template <class T>
struct InOutTypeTraits < in<T> >
{
enum {isin=1, isout=0};
};
template <class T>
struct InOutTypeTraits < out<T> >
{
enum {isin=0, isout=1};
};
template <class T>
struct InOutTypeTraits < inout<T> >
{
enum {isin=1, isout=1};
};
template <>
struct InOutTypeTraits < NullType >
{
enum {isin=0, isout=0};
};
通過(guò)另一個(gè)模板類(lèi)InList來(lái)幫我們產(chǎn)生所有的in類(lèi)型,它的結(jié)果是一個(gè)Typelist。為了方便以后使用,我把out類(lèi)型產(chǎn)生器也做了一個(gè)OutList。
template <int CONDITION, class _IF, class _ELSE>
struct If
{
typedef _IF Result;
};
template <class _IF, class _ELSE>
struct If <0, _IF, _ELSE>
{
typedef _ELSE Result;
};
template <class A = NullType, class B = NullType, class C = NullType, class D = NullType,
class E = NullType, class F = NullType, class G = NullType, class H = NullType
>
struct InList
{
typedef typename If <
InOutTypeTraits <A>::isin,
typename Typelist < A, typename InList<B,C,D,E,F,G>::Result >,
typename InList<B,C,D,E,F,G,H>::Result
>::Result Result;
};
template <class A>
struct InList <A, NullType, NullType, NullType, NullType, NullType, NullType, NullType>
{
typedef typename If <
InOutTypeTraits <A>::isin,
typename MakeTypelist <A>::Result,
typename MakeTypelist <>::Result
>::Result Result;
};
template <class A = NullType, class B = NullType, class C = NullType, class D = NullType,
class E = NullType, class F = NullType, class G = NullType, class H = NullType
>
struct OutList
{
typedef typename If <
InOutTypeTraits<A>::isout,
typename Typelist < A, typename OutList<B,C,D,E,F,G>::Result >,
typename OutList<B,C,D,E,F,G,H>::Result
>::Result Result;
};
template <class A>
struct OutList <A, NullType, NullType, NullType, NullType, NullType, NullType, NullType>
{
typedef typename MakeTypelist <A>::Result Result;
};
它的原理是,根據(jù)If模板類(lèi)來(lái)判斷一個(gè)類(lèi)型是不是in類(lèi)型,是的話(huà)就把它加入到Typelist中,不是就排除它。
InList
, in, inout, out::Result是一個(gè)Typelist , Typelist, Typelist, NullType> > >類(lèi)型,說(shuō)簡(jiǎn)單點(diǎn),它和MakeTypelist < in, in, inout >::Result是等價(jià)的。
現(xiàn)在Base模板類(lèi)將接受一個(gè)模板參數(shù),它是一個(gè)Typelist類(lèi)型,這個(gè)不詳細(xì)講了,把它的定義寫(xiě)出來(lái):
template <class T, int T_COUNT = Length <IN_TYPE>::value >
struct Base
{
Loki::CompileTimeError <false> Only_Use_Partial_Specialisation_Version;
};
template <class T>
struct Base <T, 0>
{
typedef void(*FUNC_TYPE)();
template <class FUNC_TYPE>
void async_call (FUNC_TYPE func)
{
}
void async_call ()
{
}
};
template <class T>
struct Base <T, 1>
{
typedef void(*FUNC_TYPE)(
typename TypeAt <T, 0>::Result::OriginalType);
void async_call (
typename TypeAt <T, 0>::Result::OriginalType v0,
FUNC_TYPE func)
{
}
void async_call (typename TypeAt <T, 0>::Result::OriginalType v0)
{
}
};
template <class T>
struct Base <T, 2>
{
typedef void(*FUNC_TYPE)(
typename TypeAt <T, 0>::Result::OriginalType,
typename TypeAt <T, 1>::Result::OriginalType);
void async_call (
typename TypeAt <T, 0>::Result::OriginalType v0,
typename TypeAt <T, 1>::Result::OriginalType v1,
FUNC_TYPE func)
{
}
void async_call (
typename TypeAt <T, 0>::Result::OriginalType v0,
typename TypeAt <T, 1>::Result::OriginalType v1)
{
}
};
template <class T>
struct Base <T, 3>
{
typedef void(*FUNC_TYPE)(
typename TypeAt <T, 0>::Result::OriginalType,
typename TypeAt <T, 1>::Result::OriginalType,
typename TypeAt <T, 2>::Result::OriginalType);
void async_call (
typename TypeAt <T, 0>::Result::OriginalType v0,
typename TypeAt <T, 1>::Result::OriginalType v1,
typename TypeAt <T, 2>::Result::OriginalType v2,
FUNC_TYPE func)
{
}
void async_call (
typename TypeAt <T, 0>::Result::OriginalType v0,
typename TypeAt <T, 1>::Result::OriginalType v1,
typename TypeAt <T, 2>::Result::OriginalType v2)
{
}
};
template <class T>
struct Base <T, 4>
{
typedef void(*FUNC_TYPE)(
typename TypeAt <T, 0>::Result::OriginalType,
typename TypeAt <T, 1>::Result::OriginalType,
typename TypeAt <T, 2>::Result::OriginalType,
typename TypeAt <T, 3>::Result::OriginalType);
void async_call (
typename TypeAt <T, 0>::Result::OriginalType v0,
typename TypeAt <T, 1>::Result::OriginalType v1,
typename TypeAt <T, 2>::Result::OriginalType v2,
typename TypeAt <T, 3>::Result::OriginalType v3,
FUNC_TYPE func)
{
}
void async_call (
typename TypeAt <T, 0>::Result::OriginalType v0,
typename TypeAt <T, 1>::Result::OriginalType v1,
typename TypeAt <T, 2>::Result::OriginalType v2,
typename TypeAt <T, 3>::Result::OriginalType v3)
{
}
};
這部分有點(diǎn)多,其實(shí)還是比較清晰的。注意這個(gè)Base的版本已經(jīng)不是上面所講的那個(gè)了。
函數(shù)原形推導(dǎo)問(wèn)題就講完了。上面的代碼不一定還能編譯,昨天是能編譯的,被我修改了一些,為了解釋?zhuān)指某勺蛱炷菢幼印?