使用模板元编程来包装C风格的可变参数

时间:2010-12-10 16:13:03

标签: c++ templates recursion metaprogramming

我有一个Visual Studio 2008 C ++ DLL,它导出一个接受如下变量参数的函数:

__declspec( dllexport ) void DLL_Foo( int count, ... )
{
    va_list list;
    va_start( list, count );

    for( ; count; --count )
    {
        const wchar_t* item = va_arg( list, const wchar_t* );
        if( count % 2 == 0 )
            printfW( L"[%s] ", item );
        else
            printfW( L"%s ", item );
    }

    va_end( list );

    printfW( L"\r\n" );
}

预期用法是这样的:

DLL_Foo( 4, L"int", L"1", L"const wchar_t*", L"Hello" );

输出为:

[int] 1, [const wchar_t*] Hello

为了简化这个函数的使用,我打算包含一个像这样的C ++模板函数:

template< class T1, class T2 >
void Foo( T1 p1, T2 p2 )
{
    std::wstringstream t1W;
    t1W << typeid( p1 ).name();
    std::wstringstream p1W;
    p1W << p1;

    std::wstringstream t2W;
    t2W << typeid( p2 ).name();
    std::wstringstream p2W;
    p2W << p2;

    ::DLL_Foo( 4, t1W.str().c_str(), p1W.str().c_str(), t2W.str().c_str(), p2W.str().c_str() );
};

预期用途如下:

int a = 1;
const wchar_t* b = L"Hello";
Foo( a, b );

具有与以前相同的预期输出。

我可以使用模板递归方法,这样我就不必为0..n参数实现不同的template<> Foo()函数了吗?

template<> void Foo();
template< class T1 > void Foo( T1 p1 );
template< class T1, ..., class N > void Foo( T1 p1, ..., N n );

请不要涉及可变参数模板或其他C ++ 0x功能的解决方案。我意识到他们很棒,但我正在使用VS2008。另外,为了更加困难,我无法使用boost :: MPL等增强功能。

谢谢, PaulH


编辑:是的,DLL实际的dll函数不仅仅是打印类型和值信息。实际的DLL函数看起来更像这样:

__declspec( dllexport ) void DLL_Foo( MYHANDLE handle, int count, ... )
{
    CMyObject* obj = reinterpret_cast< CMyObject* >( handle );

    va_list list;
    for( va_start( list, count ); count; --count )
    {
        const wchar_t* item = va_arg( list, const wchar_t* );
        if( count % 2 == 0 )
        {
            obj->AddTypeInfo( item );
        }
        else
        {
            obj->AddValueInfo( item );
        }
    }

    va_end( list );
}

3 个答案:

答案 0 :(得分:1)

这只能使用C ++ 0x功能。如果你不能使用它的可变参数模板,你就无法创建一个函数......呃,它需要不同数量的模板。

另一方面,可以创建同一方法的多个重载,每个重载都有自己的参数个数(1 ...某个上限)。这当然是相当多的工作。

答案 1 :(得分:1)

康拉德的回答是正确的。

但是,您可以通过Foo接受元组来避免写入多次重载,但会给您的用户带来轻微的不便,例如:

template<class TupleT>
void Foo(const TupleT& Args)

请求调用者在调用Foo时将参数包装在元组中:

//Foo(an_int, a_bool, a_whatever);
Foo(boost::make_tuple(an_int, a_bool, a_whatever));

...现在,正好我要点击“发布你的答案”按钮,我发现你不能使用Boost。你可以使用功能包吗?我认为它有std :: tr1 :: tuple。

答案 2 :(得分:0)

上次我需要做这样的事情时,我编写了一个perl脚本,可以为我生成模板。

下行是你最终需要编译很多代码,但这取决于你的最大值。