Использование шаблонного метапрограммирования для переноса аргументов в стиле C - PullRequest
2 голосов
/ 10 декабря 2010

У меня есть DLL-библиотека Visual Studio 2008 C ++, которая экспортирует функцию, которая принимает переменный параметр, подобный этому:

__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.

Спасибо, 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 ]

1 голос
/ 10 декабря 2010

Ответ Конрада правильный.

Однако вы можете избежать написания нескольких перегрузок за счет небольшого неудобства для своих пользователей, если 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.

1 голос
/ 10 декабря 2010

Это возможно только при использовании функций C ++ 0x. Если вы не можете использовать его шаблоны с переменными значениями, вы не можете создать функцию… эээ, которая принимает переменное количество шаблонов.

С другой стороны, вы можете создать несколько перегрузок одного и того же метода, каждый со своим собственным числом аргументов (1 ... некоторый верхний предел). Это, конечно, немало работы.

0 голосов
/ 10 декабря 2010

В прошлый раз, когда мне нужно было сделать что-то подобное, я написал Perl-скрипт, который генерировал бы шаблоны для меня.

Недостатком является то, что в итоге у вас будет много кода для компиляции, но это зависит от того, какой у вас максимальный уровень.

...