TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #545 4.21K
Получаем адрес стандартной функции

Иногда людям приходится работать с указателями на функции. И у них может возникнуть надобность взять адрес у стдшной функции. Например, вы хотите как-то трансформировать каждый символ в строке c помощью std::transform и в качестве коллбэка передаете именно указатель на функцию

std::transform(s.begin(), s.end(), s.begin(), std::toupper);


Вроде ничего страшного не должно случиться. Но согласно стандарту, поведение программы в этом случае unspecified и потенциально даже ill-formed.

Все потому что нельзя брать адреса у стандартных функций. Начиная с С++20 это явно прописано в стандарте.

Let F denote a standard library function, a standard 
library static member function, or an instantiation of
a standard library function template.

Unless F is designated an addressable function,
the behavior of a C++ program is unspecified
(possibly ill-formed) if it explicitly or implicitly
attempts to form a pointer to F.

Possible means of forming such pointers include
application of the unary & operator, addressof,
or a function-to-pointer standard conversion.

Moreover, the behavior of a C++ program is
unspecified (possibly ill-formed) if it attempts
to form a reference to F or if it attempts to form
a pointer-to-member designating either a standard library
non-static member function or an instantiation of
a standard library member function template.


Нельзя формировать указатели и ссылки на стандартные функции и нестатические методы.


Но почему? Чем они отличаются от обычных функций?

На самом деле ничем. Дело в том, что будет с функциями в будущем.

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

А стандарт - это штука не статичная. В него постоянно добавляются новые фичи и обновляются в том числе старые инструменты. Например, с приходом С++11 у нас появилась мув-семантика. И условный метод вектора push_back обзавелся новой перегрузкой для правой ссылки. И это сломало код, который брал адрес метода push_back.

#include <vector>

template<typename T>
void Invoke(std::vector<int>& vec, T mem_fun_ptr, int arg)
{
(vec.*mem_fun_ptr)(arg);
}

int main()
{
std::vector<int> vec;
Invoke(vec, &std::vector<int>::push_back, 42);
}


Этот код успешно собирается на 98 плюсах, но не может этого сделать на 11-м стандарте. Можете поиграться с примером на годболте.

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

std::transform(s.begin(), 
s.end(),
s.begin(),
[](unsigned char c){ return std::toupper(c); });


Don't break your future. Stay cool.

#cppcore #cpp20
  • 👍 34
  • ❤ 7
  • 🔥 7
  • ❤‍🔥 3
  • 😱 1
More from @grokaemcpp
  1. Oct 14, 2026​​Что внутри std::condition_variable? #опытным Более менее все знакомы с примитивом синхро…
  2. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  3. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  4. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  5. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  6. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →