Отличие от nullptr тут одно. С nullptr — это гарантированное UB на уровне языка в данной конкретной строке кода, независимо от поведения других частей программы. А с fake_ptr UB, если разработчик заведомо знает, что под fake_ptr реально не размещен объект (то есть, нужно знать как работает вся программа и даже оборудование, вдруг оно размещает по данному адресу объект).
std::forward<std::string>(_name) всегда вернет rvalue ссылку std::string&&, независимо от типа ссылки _name. То есть, будет работать как std::move.
Правильно std::forward<T>(_name)
Полезным с точки зрения инкапсуляции будет, как с перегрузкой операторов. Страуструп рекомендует объявлять операторы внешней функцией, если им не требуются закрытые члены. Таким образом, при проверке инвариантов и рефакторинге внутренностей мы просматриваем только операторы-члены.
Проблемы те же: интерфейс класса распадается на на члены и свободные функции, просматиривать глазами такой интерфейс неудобно, а порой и невозможно твердо понять в куче заголовочников, может ли еще где-то быть определен метод.
Что бы вы назвали самой важной фичей языка? (Реплики из зала: «фигурные скобки», «шаблоны»). Нет. Это деструкторы. Деструкторы сделали возможным RAII. Деструкторы упростили сложность используемых в программировании концепций на порядок. В деструкторе мы можем освободить память, мьютекс, закрыть файл или сетевое соединение. Деструкторы спасают нас от веток условий, от ненужных goto.
Вопрос «зачем?» — был не мой. Каждый свободен в выборе любимых инструментов. Меня лишь интересует техническая сторона. Как провернуть этот трюк с автоматическим деструктором на чистом C прозрачно для пользователя. Ибо это неудобство в C для меня на первом месте из-за невозможности RAII. Если это типа GCC __attribute__((cleanup (scoped))) или MSVC __try __finally. Тогда вопрос снят.
Вы сейчас о полиморфности и виртуальном деструкторе. Не спорю, это на C реализуется.
Ключевое здесь:
при том, что пользователь вызывал одну и ту же функцию «delete()»
= пользователь забыл вызвать / 2 раза вызвал / рано вызвал / не там вызвал…
В C++ RAII сделает этот вызов за вас, какой бы запутанности не был код, о чем и пытается втолковать Вам jcmvbkbc.
Очень бы хотелось увидеть пример кода, когда при выходе из области видимости в C можно исполнить некий код. Я знаю только платформозависимые конструкции, типа __try __finally в MSVC.
А насчет delete в C++: я не использую оператор delete вообще (разве что в самых низкоуровневых частях библиотек) и никому не советую. И в очень редких случаях приходится использовать new. Так что наваять new / delete на C — нет проблем, только зачем эти операторы, которые не очень согласуются с идиомами C++ (типа RAII)?
Пару вопросов:
1) А почему бы не использовать recursive_mutex? Или лучше задать тип мьютекса дополнительным параметром шаблона. Тогда можно и разрешить копировать Accessor, и множественно вызывать SharedResource::lock().
2) Поддержка const SharedResource намеренно отсутствует? Можно реализовать, сделав m_mutex mutable и добавив класс ConstAccessor, который будет возвращаться из SharedResource::lock() const.
так как позволяет писать typedef TypeList<int,char,bool,string, EmptyList> MyTypeList;
вместо классической записи typedef TypeList<int,TypeList<char,TypeList<bool,TypeList<string, EmptyList>>>> MyTypeList;
Мне не приходилось пользоваться Loki (предпочитаю boost::mpl), но, тем не менее, я заглядывал в исходники из любопытства. Там есть мейкеры для TypeList: typedef MakeTypelist<int,char,bool,string>::Result MyTypeList;
Также на макросах: typedef LOKI_TYPELIST_4(int,char,bool,string) MyTypeList;
Именно такой подход сразу и пришел мне в голову: через mpl::equal выражать. Это менее красиво, в разы тормознее, но формально правильно по спецификации mpl, ничего тут не поделаешь.
Справедливости ради, вместо вектора там вообще может быть все что угодно
Я о том же выше и написал, что неспецифицировано. Например, для операции mpl::erase гарантируется лишь, что результат будет «concept-identical» источнику. То есть, с сохранением набора концепций, но фиг знает каким классом.
A sequence s1 is said to be concept-identical to a sequence s2 if s1 and s2 model the exact same set of concepts.
На практике из mpl::vector[N] будет получаться mpl::vectorN-1, я бы мог забить вторую спецификацию mpl::vector1<int> и, уверен, 100 лет бы проработало, но формально — это ошибка.
принимать конкретно ваши (fas::) списки типов
К сожалению, fas — не моя, это laphroaig :)
Ни сколько не умаляю достоинств mpl. Сам пользуюсь. Ее возможности более широкие. Широченные. А за высокий уровень абстрагирования приходится платить временем компиляции.
Да, помню, как я раздосадовался, когда хотел красиво специализацией раздиспатчить что-то типа:
template <typename V>
class C{};
template <>
class C<mpl::vector<int> >{};
Не специфицировано, что может получиться после манимуляций с вектором (получится, конечно, тот же вектор как концепт, но имя у него может быть vector0, vector1 и т.д.). По факту у меня мог прийти mpl::vector1<int> или mpl::vector<int>
Нашему бизнесу не только пофиг. Он еще посодействовать не прочь. На примере Яндекса и LiveJournal, случайно наткнулся на этой неделе: www.e-xecutive.ru/blog/Easy_Eco/15385.php
Сам пробовал, действительно Яндекс именно ту статью про Барака не находит (хотя опубликована она на нескольких сайтах), даже если указать ему на каком сайте искать и вбивать в запрос заголовок, теги, все равно не находит. Судить не берусь, может, на это какие-то другие причины есть, не пытался исследовать, может баг. Google прекрасно выводит первыми ссылками на странице.
Полностью согласен. Можно улучшать, можно придумать еще кучу способов. Главное, что способ с std::function не единственный и далеко не самый эффективный.
А все от того, что бытует мнение, что лямбды — объекты неизвестного типа. С decltype тип вполне известен.
Стараюсь не оборачивать лишний раз лямбды в std::function из-за лишнего оверхеда, особенно, когда лямбда не влезает в small buffer optimization.
std::forward<std::string>(_name)
всегда вернет rvalue ссылкуstd::string&&
, независимо от типа ссылки _name. То есть, будет работать какstd::move
.Правильно
std::forward<T>(_name)
static_cast<concrete_type*>(base_ptr)->concrete_type::function(args...)
std::tie(x, y) = getPosition();
А код часто приходится читать глазами в текстовых редакторах, в репозиториях… Читаемый интерфейс класса — это важно.
Проблемы те же: интерфейс класса распадается на на члены и свободные функции, просматиривать глазами такой интерфейс неудобно, а порой и невозможно твердо понять в куче заголовочников, может ли еще где-то быть определен метод.
Ключевое здесь:
= пользователь забыл вызвать / 2 раза вызвал / рано вызвал / не там вызвал…
В C++ RAII сделает этот вызов за вас, какой бы запутанности не был код, о чем и пытается втолковать Вам jcmvbkbc.
А насчет delete в C++: я не использую оператор delete вообще (разве что в самых низкоуровневых частях библиотек) и никому не советую. И в очень редких случаях приходится использовать new. Так что наваять new / delete на C — нет проблем, только зачем эти операторы, которые не очень согласуются с идиомами C++ (типа RAII)?
Пару вопросов:
1) А почему бы не использовать recursive_mutex? Или лучше задать тип мьютекса дополнительным параметром шаблона. Тогда можно и разрешить копировать Accessor, и множественно вызывать SharedResource::lock().
2) Поддержка const SharedResource намеренно отсутствует? Можно реализовать, сделав m_mutex mutable и добавив класс ConstAccessor, который будет возвращаться из SharedResource::lock() const.
Мне не приходилось пользоваться Loki (предпочитаю boost::mpl), но, тем не менее, я заглядывал в исходники из любопытства. Там есть мейкеры для TypeList:
typedef MakeTypelist<int,char,bool,string>::Result MyTypeList;
Также на макросах:
typedef LOKI_TYPELIST_4(int,char,bool,string) MyTypeList;
Я о том же выше и написал, что неспецифицировано. Например, для операции mpl::erase гарантируется лишь, что результат будет «concept-identical» источнику. То есть, с сохранением набора концепций, но фиг знает каким классом.
На практике из mpl::vector[N] будет получаться mpl::vectorN-1, я бы мог забить вторую спецификацию
mpl::vector1<int>
и, уверен, 100 лет бы проработало, но формально — это ошибка.К сожалению, fas — не моя, это laphroaig :)
Ни сколько не умаляю достоинств mpl. Сам пользуюсь. Ее возможности более широкие. Широченные. А за высокий уровень абстрагирования приходится платить временем компиляции.
Не специфицировано, что может получиться после манимуляций с вектором (получится, конечно, тот же вектор как концепт, но имя у него может быть vector0, vector1 и т.д.). По факту у меня мог прийти
mpl::vector1<int>
илиmpl::vector<int>
Пришлось извращаться менее красиво.
Ну почему же? MPL тоже работает со списками и с другими классами и концепциями последовательностей, а также итераторов.
А получилось здорово, конечно.
Сам пробовал, действительно Яндекс именно ту статью про Барака не находит (хотя опубликована она на нескольких сайтах), даже если указать ему на каком сайте искать и вбивать в запрос заголовок, теги, все равно не находит. Судить не берусь, может, на это какие-то другие причины есть, не пытался исследовать, может баг. Google прекрасно выводит первыми ссылками на странице.
А все от того, что бытует мнение, что лямбды — объекты неизвестного типа. С decltype тип вполне известен.
Стараюсь не оборачивать лишний раз лямбды в std::function из-за лишнего оверхеда, особенно, когда лямбда не влезает в small buffer optimization.
Способ №2:
Способ №3:
Способ №4:
И т. д…