При передаче фукнции в другую функцию, может быть соблазн использовать не тип указателя на функцию, а тип функции. Должен же приводиться.
Так вот, в некоторых сценариях студия (проверено на MSVC 2012) падает, пытаясь разыменовать инструкции функции.
Воспроизводится как с объявлением функции-параметра напрямую, так и через typedef.
Был способ и без лябмды, но не получается его легко рафинировать.
Решение — не выделываться, объявлять через указатель.
#include <algorithm>
#include <iostream>
static void c(int v) { std::cout << v; };
//void f(int* a, size_t count, void (*callback)(int)) //- так не падает
void f(int* a, size_t count, void callback(int))
{
std::for_each(
a,
a + count,
[callback] (int v) { callback(v); } );
}
int main()
{
int x[5] = {};
f(x, 5, c);
return 0;
}
Хм, проверил в студии-2003.
Так падает:
| Скрытый текст |
| template <typename F>
void Test (const F& f)
{
int i=5;
f(i);
}
void Foo(int i)
{
printf("%i\n", i);
}
void Bar(void callback(int))
{
Test(callback);
}
int main ()
{
Bar(Foo);
getchar();
return 0;
}
|
| |
а так не падает:
| Скрытый текст |
| template <typename F>
void Test (F f)
{
int i=5;
f(i);
}
void Foo(int i)
{
printf("%i\n", i);
}
void Bar(void callback(int))
{
Test(callback);
}
int main ()
{
Bar(Foo);
getchar();
return 0;
}
|
| |
Здравствуйте, Alexander G, T4r4sB, Вы писали:
TB>>Хм, проверил в студии-2003.
AG>Да, в 2012 то же самое на этих примерах.
оно честно пытается разыменовать ссылку, как указатель:
ms cl said:
00411BFB mov ecx,dword ptr [f]
00411BFE mov edx,dword ptr [ecx]
00411C00 call edx
что-то тут недодумано?
А так не падает:
| Скрытый текст |
|
template <typename F>
void Test (const F& f)
{
int i=5;
f(i);
}
void Foo(int i)
{
printf("%i\n", i);
}
void Bar(void callback(int))
{
Test(&callback);
}
int main ()
{
Bar(Foo);
getchar();
return 0;
}
|
| |
Короче, попробуй так:
void f(int* a, size_t count, void callback(int))
{
std::for_each(a, a + count, &callback);
}
Блин, боюсь на таких вопросах завалить теорию. Все эти неявные касты "сущность==указатель на неё" — такая муть...
Здравствуйте, T4r4sB, Вы писали:
TB>А так не падает:
TB>void Bar(void callback(int))
TB>{
TB> Test(&callback);
TB>}
потому что ты адрес передаёшь, там он там разыменовывается нормально в адрес функции.
в общем, странно, объясните кто-нибудь:
ms cl said:
int i = 0;
00411ECE mov dword ptr [i],0
AA(i);
00411ED5 lea eax,[i]
00411ED8 push eax
00411ED9 call AA (4112A3h)
00411EDE add esp,4
Test(&callback);
00411EE1 lea eax,[callback]
00411EE4 push eax
00411EE5 call Test<void (__cdecl*)(int)> (41129Eh)
00411EEA add esp,4
Test(callback);
00411EED mov eax,dword ptr [callback]
00411EF0 push eax
00411EF1 call Test<void (__cdecl*)(int)> (41129Eh)
00411EF6 add esp,4
в случае вызова с передачей параметра по ссылке, пушится указатель на переменную (00411ED8) потом внутри раскручивается.
во втором вызове мы самы пушим указатель, он внутри раскручивается, всё ок.
в третьем случае мы передаём ссылку на функцию, но компилятор её тут передаёт, как есть (00411EED), а в вызове почему-то раскручивает, как указатель. ЧМДНТ? Почему в третьем вызове компилятор не заворачивает параметр в указатель, хотя знает, что передача по ссылке?