Переопределение стандартных функций

Я хотел бы переопределить поведение стандартной функции, скажем, std::time. Можно ли вызвать std::time и перенаправить его через мою пользовательскую функцию?


person Community    schedule 03.09.2009    source источник
comment
Чтобы уточнить: я хочу перехватить использование ::time в другой предварительно скомпилированной библиотеке. Портативность не важна. Предположим, что компилятор и платформа очень специфичны и никогда не изменятся.   -  person    schedule 03.09.2009
comment
В таком случае нет, это невозможно. Не в С++. Вероятно, технически это можно сделать вне C++. Измените библиотеку времени выполнения, подключитесь к ней. Но как только библиотека скомпилирована, функции, которые она вызывает, фиксируются. Он не выполняет поиск имени и разрешение перегрузки во время выполнения. он просто вызывает функцию, которая была определена во время компиляции. И если компилятор определил, что должна быть вызвана стандартная функция std::time, то он сгенерировал код для ее вызова.   -  person jalf    schedule 03.09.2009
comment
@jalf, вам действительно следует поместить свой комментарий в ответ.   -  person Dima    schedule 04.09.2009
comment
Верно, и комментарий Тима должен был быть отредактирован в вопросе. :)   -  person jalf    schedule 04.09.2009


Ответы (5)


Вообще говоря, пространство имен std запрещено. Добавление новых функций, перегрузок, классов или чего-либо еще в пространство имен std является **неопределенным поведением*.

Единственным исключением являются специализации шаблонов. Вы можете предоставлять специализации функций в пространстве имен std. Функция, в которой это часто делается, называется std::swap.

person jalf    schedule 03.09.2009

Это звучит как очень плохая идея. Это похоже на переопределение true или false. Лучшим способом было бы написать свою собственную функцию-оболочку, скажем, tim_time(), которая может вызывать или не вызывать std::time() внутри.

person Dima    schedule 03.09.2009

Вместо того, чтобы называть его 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, она будет корректно преобразована в исходную стандартную функцию.

person P Shved    schedule 03.09.2009

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

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

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

person Steve Jessop    schedule 03.09.2009

На некоторых платформах это можно сделать. В исходном коде определите функцию, т.е.

extern "C" time_t time(time_t *value)
{
        ...
}

Если вам повезет, компоновщик свяжет вашу версию std::time более жестко, чем версию из стандартной библиотеки. Конечно, нет никакой гарантии, что это будет работать или будет связано так, как вы хотите. И, как недостаток, у вас больше нет доступа к исходному std::time.

Как уже писали все остальные, это не переносимое поведение. Я почти уверен, что это работает в Linux. Я также совершенно уверен, что это не работает в Windows (компоновщик жалуется на конфликт).

person Managu    schedule 03.09.2009