2012-04-16 4 views
9
int __cdecl ccall(int i) 
{ 
    wprintf(L"ccall(%d)", i); 
    return 0; 
} 

int __stdcall stdcall(int i) 
{ 
    wprintf(L"stdcall(%d)", i); 
    return 0; 
} 

int __cdecl wmain(int argc, wchar_t **argv) 
{ 
    std::function<int(int)> fnc = ccall; 
    std::function<int(int)> fnstd = stdcall; 

    fnc(10); // printed well 
    fnstd(100); // printed well 
    return 0; 
} 

Я был обеспокоен тем, как назначить объект __stdcall function объекту std::function. Но без какого-либо указания соглашения о вызове он выглядит как работающий нормально. Как может std::function знать, что такое конвенция?Как известно std :: function о вызове?

+2

Таким же образом компилятор знает, как вызвать функцию без 'станд :: function'. 'std :: function' использует стирание типа для создания крошечного внутреннего черного ящика, когда при вызове' std :: function' предлагается выполнить «реальный» вызов, который уже выяснил компилятор. – GManNickG

ответ

6

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

§ 20.8.11.2:

Функция шаблона класса обеспечивает полиморфные упаковщики, обобщающие понятие указателя функции. Обертки могут хранить, копировать и вызывать произвольные вызываемые объекты (20.8.1), учитывая сигнатуру вызова (20.8.1), позволяя функциям быть объектами первого класса.

Как John Calsbeekadded: Там нет ничего, в частности, в стандарте, касающихся соглашений о вызовах, но компиляторы делают свою работу и указатели на функции содержат информацию о конвенции.

С указателей на функции, которые необходимо будет указать необычное соглашение о вызовах:

typedef int(* c_ptr_t)(int); 
typedef int(__stdcall * std_ptr_t)(int); 

c_ptr_t c_ptr = ccall; 
std_ptr_t std_ptr = stdcall; 

// But std::function doesn't mind: 
std::function<int(int)> fnc = c_ptr; 
std::function<int(int)> fnstd = std_ptr; 
+5

Я не уверен, что это технически ответ, так как стандарт C++ почти не упоминает о вызове конвенции, и этого, конечно, нет. Ответ заключается в том, что 'std :: function'« запоминает »тип функции с использованием магии стирания типа, а указатели функций в большинстве разумных компиляторов содержат информацию о используемом условном вызове. –

+0

@JohnCalsbeek: Вы правы, нет ничего более подробного в стандарте, чем упоминание цитируемой части. Вызывающие соглашения являются неотъемлемой территорией, но компиляторы хорошо себя ведут и делают то, что необходимо. – Anonymous

+2

Ближайшая вещь - «C-связь». Там компилятор просто должен заставить его работать - в стандарте нет ничего, что заставило программиста отвечать. В дополнение, поскольку стандарт ничего не говорит о вызовах конвенций, это молчание снова делает его компилятором. – MSalters