Я хотел бы переопределить поведение стандартной функции, скажем, std::time. Можно ли вызвать std::time и перенаправить его через мою пользовательскую функцию?
Переопределение стандартных функций
Ответы (5)
Вообще говоря, пространство имен std
запрещено. Добавление новых функций, перегрузок, классов или чего-либо еще в пространство имен std
является **неопределенным поведением*.
Единственным исключением являются специализации шаблонов. Вы можете предоставлять специализации функций в пространстве имен std
. Функция, в которой это часто делается, называется std::swap
.
Это звучит как очень плохая идея. Это похоже на переопределение true
или false
. Лучшим способом было бы написать свою собственную функцию-оболочку, скажем, tim_time()
, которая может вызывать или не вызывать std::time()
внутри.
Вместо того, чтобы называть его std::time
, направьте все вызовы, которые вы иногда можете переопределить, через другое пространство имен.
namespace mystd{
using namespace std;
void time() { ... }
}
// ...
mystd::time(); // not std::time
mystd::copy(...); // calls std::copy, unless you override it like time()
Затем вызов mystd::time
вызовет измененную версию функции. Если вы вызываете непереопределенную функцию, например, mystd::copy
, она будет корректно преобразована в исходную стандартную функцию.
Не переносимо. При том понимании, что стандарт не определяет, что происходит, вы обычно можете определить любые символы и функции, которые вам нравятся, в пространстве имен std или связать с библиотекой, которая определяет эти символы, или что-то еще. Это просто неопределенное поведение. Так что все, что вы можете сделать, это высосать его и посмотреть, и надеяться, что он не сломается в следующем выпуске вашего компилятора.
Тем не менее, с большинством компиляторов это, вероятно, в основном будет работать, при условии, что вы избежите конфликта одного правила определения с «настоящим» std::time. Это связано с тем, что большинство компиляторов на самом деле не делают ничего особенного с пространством имен std, а файлы заголовков и библиотеки, которые они используют для его реализации, на самом деле ничем не отличаются от файлов заголовков и библиотек, которые вы могли бы написать самостоятельно.
Но Дима абсолютно прав, что выходить за рамки стандарта почти всегда очень плохая идея. Возможно, если вы застряли в каком-то аду отладки, где вы в основном хотите добавить ведение журнала в std::time, но не можете, то стоит подумать об этом. В противном случае не ходите туда. Если вы хотите протестировать некоторый код, чтобы увидеть, правильно ли он работает в разное время, передайте этому коду параметр (или параметр шаблона), указывающий, какую функцию времени он должен вызывать.
На некоторых платформах это можно сделать. В исходном коде определите функцию, т.е.
extern "C" time_t time(time_t *value)
{
...
}
Если вам повезет, компоновщик свяжет вашу версию std::time
более жестко, чем версию из стандартной библиотеки. Конечно, нет никакой гарантии, что это будет работать или будет связано так, как вы хотите. И, как недостаток, у вас больше нет доступа к исходному std::time
.
Как уже писали все остальные, это не переносимое поведение. Я почти уверен, что это работает в Linux. Я также совершенно уверен, что это не работает в Windows (компоновщик жалуется на конфликт).