C ++ 11 Шаблонная функция, которая принимает std :: function, которая зависит от параметров шаблона - PullRequest
5 голосов
/ 30 сентября 2011

Я пытаюсь написать шаблонную функцию, которая принимает std::function, которая зависит от аргументов шаблона.К сожалению, компилятор не может правильно определить аргументы для std::function.Вот простой пример кода:

#include <iostream>
#include <functional>

using namespace std;

void DoSomething( unsigned ident, unsigned param )
{
    cout << "DoSomething called, ident = " << ident << ", param = "  << param << "\n";
}

template < typename Ident, typename Param >
void CallFunc( Ident ident, Param param, std::function< void ( Ident, Param ) > op )
{
    op( ident, param );
}

int main()
{
    unsigned id(1);
    unsigned param(1);

    // The following fails to compile
    // CallFunc( id, param, DoSomething );

    // this is ok 
    std::function< void ( unsigned, unsigned ) > func( DoSomething );
    CallFunc( id, param, func ); 

    return 0;
}

Если я вызываю шаблон со следующим:

CallFunc( id, param, DoSomething );

Я получаю следующие ошибки:

function-tpl.cpp: 25: ошибка: нет соответствующей функции для вызова CallFunc(unsigned int&, unsigned int&, void (&)(unsigned int, unsigned int))

Если я явно создаю std :: function правильного типа (или приведу ее), проблема исчезнет:

std::function< void ( unsigned, unsigned ) > func( DoSomething );
CallFunc( id, param, func );

Как бы я закодировал это, чтобы явный временный указатель не был необходим?

Ответы [ 3 ]

8 голосов
/ 30 сентября 2011

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

template < typename T > struct id { typedef T type; };

template < typename Ident, typename Param >
void CallFunc( Ident ident, Param param, 
               typename id<std::function< void ( Ident, Param ) >>::type op )
{
    op( ident, param );
}

Вместо id вы можете использовать boost::identity.В C ++ 0x и компиляторах, которые его поддерживают, вы можете иметь более читаемую версию с использованием шаблонов псевдонимов

template < typename T > using nondeduced = typename id<T>::type;

Тогда ваш код становится просто

template < typename Ident, typename Param >
void CallFunc( Ident ident, Param param, 
               std::function< nondeduced<void ( Ident, Param )> > op )
{
    op( ident, param );
}

Однако GCC пока не поддерживаетшаблоны псевдонимов.

2 голосов
/ 30 сентября 2011

Если вы используете шаблоны, вы можете полностью исключить std::function, если только по какой-то причине вы не хотите специально ограничить функцию принятием std::function:

template < typename Ident, typename Param, typename Func >
void CallFunc( Ident ident, Param param, Func op )
{
    op( ident, param );
}
0 голосов
/ 30 сентября 2011

Вы можете сделать преобразование встроенным или использовать bind. Ни один из них не особенно хорош, но они выполняют свою работу :

CallFunc(id, param, std::function<void(unsigned, unsigned)>(DoSomething));

CallFunc(id, param, std::bind(DoSomething, std::placeholders::_1, std::placeholders::_2));

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...