Почему boost рекомендует использовать основные функции, а не функции-члены?

В документации для boost .geometry говорится

Примечание: предпочтительнее использовать x = bg::get:‹0>(point1);
(в отличие от x = point1.get‹0>();)

Я видел это в другом месте в документации по повышению. Мой вопрос: почему? Является ли это передовой практикой, производительностью или какой-то причудой? Это общее правило или конкретное для этой библиотеки?


person mmdanziger    schedule 21.01.2014    source источник
comment
Для существующего типа точки (предоставленного кем-то другим) вы можете реализовать бесплатную функцию get, которая воздействует на него, но вы не можете добавить функцию-член get, поэтому она более общая.   -  person Marc Glisse    schedule 21.01.2014
comment
@MarcGlisse, но не будет ли внешний тип точки (если он получен из базового класса) в любом случае обязательно иметь get? Это единственная причина?   -  person mmdanziger    schedule 21.01.2014
comment
Если point1 имеет зависимый тип, вам также не нужно писать point1.template get<0>().   -  person Simple    schedule 21.01.2014


Ответы (1)


Это не ускорение как таковое, а современный дизайн C++ API.

  • Не требуя функций-членов, вы можете адаптировать свои собственные классы и даже типы сторонних библиотек для работы с API Boost по вашему выбору. (Таким образом, вы можете, например, сделать типы из сторонней библиотеки сериализуемыми в архив Boost Serialization).

  • Кроме того, делая функции свободными, улучшается разделение зависимостей. Например: fusion/tuple.hpp не нужно зависеть ни от чего, связанного с вводом-выводом, поскольку потоковые операции являются бесплатными функциями и, следовательно, могут быть объявлены (и определены) в отдельном заголовке: fusion/tuple_io.hpp.

  • Это также помогает инкапсуляции, потому что по умолчанию бесплатные функции не являются friends основного класса (и поэтому не могут получить доступ к закрытым членам).

  • бесплатные функции могут «делать правильные вещи» на основе ADL:

    using std::swap;
    swap(a, b); // will lookup `swap` in the namespaces that declare the parameter types
    

    (несколько других пространств имен также используются для поиска)

  • Наконец, бесплатные функции могут в общем обслуживать группу типов, которые не обязательно должны быть связаны с объектно-ориентированными объектами (связанными с наследованием). Таким образом, бесплатные функции помогают избежать дублирования кода.

Изменить Ответ на вопрос, почему вам следует предпочесть синтаксис, не являющийся членом, если оба существуют:

  • он работает для типов, которые не имеют функции-члена
  • он не требует устранения неоднозначности .template в коде шаблона (как указано @Simple)
  • Опять же: это не зависит от повышения.

    • c++03 has had std::swap() as a free function
    • С++ 11 представляет std::begin() и std::end() как бесплатные функции
    • std::hash<>, std::less<>, std::greater<>, std::equal_to<> аналогичным образом предоставляют точки настройки, которые не являются навязчивыми (но, конечно, не являются функциями).
person sehe    schedule 21.01.2014
comment
Не по теме: ради интереса, какой вариант использования для настройки std::less вместо бесплатного operator<? Вы правы в том, что он обеспечивает точку настройки, но я думаю, что это довольно неясно: вы хотите, чтобы ваш тип был сопоставим по алгоритмам и контейнерам, но не по коду, который пишут нормальные люди ;-) Есть ли какие-то раздражающие последствия частичная специализация означает, что иногда приходится мириться с этим? - person Steve Jessop; 21.01.2014
comment
@SteveJessop Самая раздражающая вещь с бесплатными функциями, о которой я могу думать, это Ловушки ADL, т. е. что ADL также может легко DoTheWrongThing(TM). Нет никакого способа контролировать ADL (кроме запрета). Да, авторы библиотек могут (и должны) защищаться от этого (используя барьерные пространства имен ADL). Но объекты-функции обладают особым свойством: они не участвуют в ADL по определению. (Я знаю, что Эрик Ниблер выступал за это и использовал его в качестве принципа при разработке Proto0x). - person sehe; 21.01.2014
comment
Я не знаю, был ли это принцип проектирования стандартной библиотеки. Возможно, они просто хотели иметь возможность, например. создавать экземпляры типов контейнеров с конкретным типом компаратора, в отличие от необходимости всегда инициализировать какой-либо универсальный тип функции с конкретным экземпляром объекта при построении. - person sehe; 21.01.2014
comment
да, я вижу причины существования std::less. Он просто использует его как точку настройки для определяемого пользователем типа, что меня озадачивает: это разрешено, но я не думаю, что когда-либо делал это. - person Steve Jessop; 21.01.2014