Что такое объекты точек настройки?
Это экземпляры объектов-функций в пространстве имен std
, которые выполняют две задачи: сначала безоговорочно инициируют (концептуальные) требования к типу для аргумента(ов), затем направляют в правильную функцию в пространстве имен. std
или через ADL.
В частности, почему они являются объектами?
Это необходимо, чтобы обойти вторую фазу поиска, которая напрямую вводит предоставленную пользователем функцию через ADL (это должно быть отложено по замыслу). Подробности смотрите ниже.
... и как их использовать?
При разработке приложения: вы в основном этого не делаете. Это стандартная библиотечная функция, она добавит проверку концепции к будущим точкам настройки, что, как мы надеемся, приведет, например. в четких сообщениях об ошибках, когда вы испортили экземпляры шаблона. Однако при квалифицированном вызове такой точки настройки вы можете использовать ее напрямую. Вот пример с воображаемым объектом std::customization_point
, который соответствует дизайну:
namespace a {
struct A {};
// Knows what to do with the argument, but doesn't check type requirements:
void customization_point(const A&);
}
// Does concept checking, then calls a::customization_point via ADL:
std::customization_point(a::A{});
В настоящее время это невозможно, например. std::swap
, std::begin
и тому подобное.
Объяснение (краткое изложение N4381)
Позвольте мне попытаться переварить предложение, стоящее за этим разделом стандарта. Есть две проблемы с «классическими» точками настройки, используемыми стандартной библиотекой.
Их легко ошибиться. Например, обмен объектами в универсальном коде должен выглядеть следующим образом.
template<class T> void f(T& t1, T& t2)
{
using std::swap;
swap(t1, t2);
}
но вместо этого сделать квалифицированный вызов std::swap(t1, t2)
слишком просто — предоставленный пользователем swap
никогда не будет вызван (см. N4381, Мотивация и область применения)
- #P11# <блочная цитата> #P12# блочная цитата>
Решение, описанное в предложении, смягчает обе проблемы с помощью подхода, подобного следующему, воображаемой реализации std::begin
.
namespace std {
namespace __detail {
/* Classical definitions of function templates "begin" for
raw arrays and ranges... */
struct __begin_fn {
/* Call operator template that performs concept checking and
* invokes begin(arg). This is the heart of the technique.
* Everyting from above is already in the __detail scope, but
* ADL is triggered, too. */
};
}
/* Thanks to @cpplearner for pointing out that the global
function object will be an inline variable: */
inline constexpr __detail::__begin_fn begin{};
}
Во-первых, квалифицированный вызов, например. std::begin(someObject)
всегда обходит через std::__detail::__begin_fn
, что желательно. О том, что происходит с неквалифицированным вызовом, я снова ссылаюсь на исходную статью:
В случае, когда begin вызывается unqualified после включения std::begin
в область действия, ситуация иная. На первом этапе поиска имя begin преобразуется в глобальный объект std::begin
. Поскольку поиск нашел объект, а не функцию, второй этап поиска не выполняется. Другими словами, если std::begin
является объектом, то using std::begin; begin(a);
эквивалентно std::begin(a);
, которое, как мы уже видели, выполняет поиск в зависимости от аргумента от имени пользователя.
Таким образом, проверка концепций может выполняться внутри функционального объекта в пространстве имен std
, перед выполнением ADL-вызова предоставленной пользователем функции. Обойти это невозможно.
person
lubgr
schedule
27.11.2018