Соглашение о связях C / C ++

При вызове алгоритмов C ++, таких как copy_if, transform и т. Д., Которые в качестве последнего аргумента принимают унарную или двоичную функцию, могу ли я передать функцию библиотеки C, например, atoi или tolower.

Например, ниже звонки работают нормально и дают правильный вывод (пробовал в ideone)

1) transform (foo, foo+5, bar, atoi);
2) transform (foo, foo+5, bar, ptr_fun(atoi));
3) transform(s.begin(),s.end(),s.begin(), static_cast<int (*)(int)>(tolower));

Гарантируется ли это использование со всеми компиляторами C ++?

В книге «Размышление на С ++» упоминается «Это работает с некоторыми компиляторами, но это не обязательно». Упомянутая причина (как я понимаю), transform является функцией C ++ и ожидает, что ее последний аргумент будет иметь такое же соглашение о вызовах.

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

// tolower_wrapper.cpp
string strTolower(string s) {
transform(s.begin(), s.end(), s.begin(), tolower);
return s;
}

Это работает нормально, но я не понял, как это решает проблему соглашения о вызовах?
transform по-прежнему является функцией c ++, а tolower по-прежнему является функцией C в strTolower, так как здесь обрабатываются различные соглашения о вызовах.

8

Решение

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

Указатель на функцию — это просто указатель на функцию, которая ожидает получить определенный набор параметров и вернуть определенный тип.

Функциональный объект является экземпляром класса, который имеет переопределенный оператор ().

При расширении шаблона алгоритма компилятор сможет увидеть, какой из двух случаев применим, и сгенерирует соответствующий код вызова.

В случае, когда функция C используется в качестве двоичной функции в алгоритме, это указатель на функцию, который вы предоставляете. Вы можете вызывать функцию C из C ++, если она объявлена extern C { ... },

Многие компиляторы поставляются с заголовочными файлами для функций библиотеки C, которые включают что-то вроде этого:

#ifdef  __cplusplus
extern "C" {
#endif

/* function declarations here */

#ifdef  __cplusplus
}
#endif

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

Другая проблема заключается в том, что вам не разрешено приводить указатели функций к типу с другой языковой связью, что, по крайней мере, в некоторых ваших примерах вы делаете, хотя некоторые компиляторы, кажется, разрешают это в любом случае — например, посмотрите это Ошибка GCC.

Другой улов, который относится конкретно к tolower Например, некоторые имена функций библиотеки C также являются именами функций или шаблонов в библиотеке C ++ std. Например, имя tolower также определяется в <locale>, Этот конкретный случай обсуждается в этом Отчет об ошибках GCC. Использование оболочки, скомпилированной в отдельном модуле компиляции, который не включает конфликтующие объявления, решит эту проблему.

2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector