Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > специализация ф-ции для function<void()>


Автор: borisbn 28.2.2012, 11:32
Здравствуйте.
Следующий код
Код

#include <functional>
#include <iostream>

template< class Arg >
void foo( std::function< void(Arg) > f ) {
    std::cout << "foo< Arg >" << std::endl;
}

template<>
void foo< void >( std::function< void(void) > f ) {
    std::cout << "foo< void >" << std::endl;
}

//template<>
//void foo< float >( std::function< void(float) > f ) {
//    std::cout << "foo< float >" << std::endl;
//}

void i_func( int ) {}
void v_func() {}
void f_func( float ) {}

int main()
{
    std::function< void(int) > i_f( i_func );
    foo( i_f );
    std::function< void() > v_f( v_func );
    foo( v_f );
//    std::function< void( float ) > f_f( f_func );
//    foo( f_f );
}

http://liveworkspace.org/code/3b891bff696e9ea5a89efd162fb93933
выдаёт ошибку
Цитата

error: template-id 'foo<void>' for 'void foo(std::function<void()>)' does not match any template declaration
error: no matching function for call to 'foo(std::function<void()>&)'
note: candidate is:
note: template<class Arg> void foo(std::function<void(Arg)>)

Причём, если закомментировать все "void"-функции и раскомментировать "float", то всё работает.
Не могу понять, это какой-то глюк или всё так и должно быть ?
Как обойти это - я уже нашёл (SFINAE = enable_if + is_void), но хотелось бы понять, в чём здесь дело.
Спасибо.

Автор: azesmcar 28.2.2012, 11:46
Цитата(borisbn @  28.2.2012,  11:32 Найти цитируемый пост)
Не могу понять, это какой-то глюк или всё так и должно быть ?

Все же void(T) и void(void) это немного разные вещи, void(void) - это тот же void() и компилятор не может найти шаблонную функцию.

Почему бы не сделать вот так?
http://liveworkspace.org/code/aed04e13fed108f260d5547b7322db45
или можно через перегрузку
http://liveworkspace.org/code/0a23eab68ffd54626dce71a6127f0cad


Автор: boostcoder 28.2.2012, 12:00
все равно не понимаю, почему не работает вариант borisbn`а...

Автор: boostcoder 28.2.2012, 12:15
ааа, въехал! smile 
ну да, <void> и <void(void)> это же разные типы)

Автор: borisbn 28.2.2012, 12:19
azesmcar, спасибо. Первый вариант мне не подходит, т.к. в первую функцию можно подать функцию, принимающую два аргумента или возвращающую не void, а вот второй - то, что надо. Как-то я не сообразил, что специализация, с одной стороны - это та же перегрузка, но с другой стороны налагает некоторые ограничения.

Автор: borisbn 28.2.2012, 14:24
Цитата(boostcoder @  28.2.2012,  12:15 Найти цитируемый пост)
ну да, <void> и <void(void)> это же разные типы)

неа. у меня там не void и void(void), а void( T ) и void().
мдаааа. а вот такая специализация работает:
Код

template< class Res >
void foo( std::function< Res() > f ) {
    cout << "foo< Arg >" << endl;
}

template<>
void foo< void >( std::function< void() > f ) {
    cout << "foo< void >" << endl;
}

int i_func() {}
void v_func() {}

int main()
{
    std::function< int() > i_f( i_func );
    foo( i_f );
    std::function< void() > v_f( v_func );
    foo( v_f );
}

http://liveworkspace.org/code/296038cd2a53b273b57b051b93d6fb7a
хотя, на первый взгляд, это - вещи похожие

Автор: azesmcar 28.2.2012, 14:31
Цитата(borisbn @  28.2.2012,  14:24 Найти цитируемый пост)
неа. у меня там не void и void(void), а void( T ) и void().

void() и void(T), это разные вещи.

Цитата(borisbn @  28.2.2012,  14:24 Найти цитируемый пост)
мдаааа. а вот такая специализация работает:

все верно, возвращяемый тип частью сигнатуры функции не является. smile 

Автор: borisbn 28.2.2012, 14:57
Цитата(azesmcar @  28.2.2012,  14:31 Найти цитируемый пост)
возвращяемый тип частью сигнатуры функции не является.

не знал... так по этому нельзя перегружать функции, если они отличаются только возвращаемым значением...

и всё равно остаётся непонятным - чем принципиально следующий код отличается от первого?
Код

template< class T >
struct S { T x; };

template< class T >
void foo( std::vector< S< T > > ) {
    cout << "foo( std::vector< S< T > > )" << endl;
}

template<>
void foo<float>( std::vector< S< float > > ) {
    cout << "foo( std::vector< S< float > > )" << endl;
}

std::vector< S< int > > i_v;
std::vector< S< float > > f_v;

int main() {
    foo( i_v );
    foo( f_v );
}

http://liveworkspace.org/code/bc1be32edad9db5581518a7d69366a42
будем считать, что std::vector в данном примере - это std::function в первом...

Автор: azesmcar 28.2.2012, 15:05
borisbn

Вот пример попроще.
Код

#include <iostream>
#include <vector>

template <class T> void foo(void(*)(T)) {}
template <> void foo(void(*)(void)) {}

int main()
{
}

компилятор пытается найти функцию foo с таким параметром, но не находит.

Автор: boostcoder 28.2.2012, 15:06
Цитата(azesmcar @  28.2.2012,  14:31 Найти цитируемый пост)
возвращяемый тип частью сигнатуры функции не является.

кстати да, вспомнил про обсуждение на некотором форуме.
Цитата

В случае обычной функции (не являющейся специализацией шаблона) — не является. Определение понятия "сигнатура функции" дано в C++11 — 1.3.17:
Цитата

signature
<function> name, parameter type list (8.3.5), and enclosing namespace (if any)

Сигнатура функции и тип функции — не одно и то же (эти два понятия часто путают).

Автор: borisbn 28.2.2012, 15:39
кажется начинаю понимать: если в параметрах функции указано энное количество аргументов (пусть и шаблонных), то все специализации обязаны поддержать эту сигнатуру, а void - это не такой же тип, как и все остальные, а отсутствие параметра.
Вот пример ещё проще
Код

template< class T >
void foo( T ) { cout << "foo( T )" << endl; }

template<>
void foo<void>( void ) { cout << "foo()" << endl; }

int main() {
    foo( 42 );
    foo();
}

http://liveworkspace.org/code/d632e6c8ba6bd8ba475ff271d1374f59

Автор: azesmcar 28.2.2012, 16:01
Цитата(borisbn @  28.2.2012,  15:39 Найти цитируемый пост)
void - это не такой же тип, как и все остальные, а отсутствие параметра

 smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)