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

发布于 2024-10-06 17:20:26 字数 2168 浏览 2 评论 0原文

我有一个 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 );

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

是否有我可以采用的模板递归方法,这样我就不必实现不同的 template>> Foo() 函数有 0..n 个参数?

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 等 boost 功能。

谢谢, 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 );
}

I have a Visual Studio 2008 C++ DLL that exports a function that accepts a variadic parameter like this:

__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" );
}

The expected usage is something like this:

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

Where the output would be:

[int] 1, [const wchar_t*] Hello

To simplify the usage of this function, I intend to include a C++ template function like this:

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() );
};

Where the expected usage is like this:

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

With the same expected output as before.

Is there a template recursion method I can employ so that I don't have to implement a different template<> Foo() function for 0..n parameters?

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

Please, no solutions involving variadic templates or other C++0x features. I realize they're wonderful, but I'm using VS2008. Also, just to be more difficult, I cannot make use of boost functionality like boost::MPL.

Thanks,
PaulH


Edit: Yes, the DLL actual dll function does more than print the type and value information. The actual DLL function looks a bit more like this:

__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 );
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

戏蝶舞 2024-10-13 17:20:26

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

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

This is only possible using C++0x features. If you cannot use its variadic templates, you cannot create a function … uh, that takes a variable number of templates.

On the other hand, you can create multiple overloads of the same method, each with its own number of arguments (1 … some upper limit). That’s of course quite a bit of work.

送君千里 2024-10-13 17:20:26

康拉德的回答是正确的。

但是,您可以通过让 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。

Konrad's answer is right.

However, you could avoid writing the multiple overloads at the cost of a slight inconvenience for your users by having Foo accept a tuple, something like:

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

And ask the caller to wrap the arguments in a tuple when calling Foo:

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

... and now, right as I am about to click the "Post Your Answer" button, I see that you can't use Boost. Can you use the feature pack? I think it has std::tr1::tuple.

苯莒 2024-10-13 17:20:26

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

缺点是您最终需要编译大量代码,但这取决于您的最大值。

The last time I needed to do something like this I wrote a perl script that would generate the templates for me.

Downside is you end up with a lot of code to compile, but it depends on what your max is.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文