Pull to refresh
56
0
Сергей Садовников @FlexFerrum

Пользователь

Send message
Занятно то, что «большие конторы» тоже сталкиваются с аналогичной проблемой. Как правильно было замечено в статье (да и не только) начиная с уровня middle спрос превышает предложение. Грамотные спецы — так и вовсе на перечёт, и не редко знают друг друга по нику/имени, а то и вовсе в лицо. А так — всё от человека-соискателя зависит. Рыпнулся с насиженного места — теперь ищи работу, где за «ничего не делать» будут платить больше. Ну или учись работать. Тут уж не знаю, что проще… Это добавляет много головной боли тому, кто собеседует но… А что делать? Да, а времени — увы, жалко…
Если руководитель маленькой IT-конторы не в состоянии адекватно оценить соискателя (а ведь он точно знает — кто ему нужен, для какой работы и с какими скилами), то, увы, ему уже никак не быть…
По поводу хитросплетений объектов — интерфейс кланга настолько широкий, что позволяет выполнить одно и то же действие несколькими различными способами. И у каждого варианта будут свои особенности.
Всё достаточно просто:
class ScopeExitCreator
{
public:
    template<typename Fn>
    ScopeExit<Fn> operator << (const Fn &fn)
    {
        return ScopeExit<Fn>(fn);
    }
};

#define EXIT_SCOPE_CREATE_UNIQ_NAME2(line) exit_scope_guard_##line
#define EXIT_SCOPE_CREATE_UNIQ_NAME(line) EXIT_SCOPE_CREATE_UNIQ_NAME2(line)
#define EXIT_SCOPE const auto  &EXIT_SCOPE_CREATE_UNIQ_NAME(__LINE__) = ScopeExitCreator() << [&]()

(класс ScopeExit тот же)
Ну и использование:
int main()
{
    std::cout << "Outer scope enter" << std::endl;
    EXIT_SCOPE{std::cout << "Outer scope exited" << std::endl;};

    {
        std::cout << "Inner scope enter" << std::endl;

        EXIT_SCOPE{std::cout << "Inner scope exited" << std::endl;};
        std::cout << "Inner scope exit" << std::endl;
    }

    std::cout << "Outer scope exit" << std::endl;
    return 0;
}


Но тут есть одна тонкость связанная больше со стилем кодирования. Декларирования макросов без параметров лучше всё-таки избегать. Резко увеличивается вероятность неожиданной коллизии.
Задам вопрос так. А вы пытались откомпилировать приведенные примеры и проверить — находятся ли, например, пути к стандартным заголовкам или нет? Может быть, конечно, я недостаточно внимательно посмотрел исходники Tooling, но у меня сложилось впечатление (и комментарии к классам это впечатление усилили), что основное ее назначение — позволить клиентскому коду обработать за один раз сразу несколько исходных файлов. И никаких специальных. Впрочем, я мог и ошибиться, и не туда посмотреть.
Думаю, это очевидно, что основной сценарий использования EXIT_SCOPE такой же, как и метода atexit. Если разработчик не понимает, зачем нужен инструмент, то, очевидно, незачем этот инструмент использовать. И, кстати, ваши первые два примера кода не эквивалентны друг другу.
Есть, кстати, возможность доточить этот код до вариант «без дополнительных скобочек».
Я ведь не зря привёл пример с atexit. Да и объект в начале функции — тоже не поможет. Сейчас SCOPE_EXIT подчиняется общим правилам control flow программы. Если выполнение до него не дошло — ничего не вызовется. Если дошло — то вызовется. Изменять эту логику на что-то более хитрое — вот это то как раз опасно, потому что появится сущность, которая «волшебным образом» будет работать по другим правилам. Чем проще контракт — тем проще его понять, и проще пользоваться.
А как, по вашему, это должно работать, чтобы ещё и в правила и соглашения языка C++ укладываться? Пока то, что вы написали, похоже примерно на следующее: написать в конце метода main кучу вызовов библиотечной функции atexit, а потом удивляться — почему ничего не работает…
Если разобраться, то clangTooling не делает ничего особенного. Тут ведь как — основная работа по разбору опций командной строки сосредоточена в библиотеке clangDriver. И она используется из clangFrontend при создании экземпляра CompilerInvocation. Собственно, результаты этой работы не раз видел в отладчике.
Опять же. Если мы говорим о C++11 то, мне кажется, есть более простой вариант без использования рантайм-полиморфизма:

template<typename F>
class ScopeExit
{
public:
    ScopeExit(const F& fn) : m_fn(fn) {;}
    ~ScopeExit()
    {
        m_fn();
    }
private:
    F m_fn;
};

template<typename F>
ScopeExit<F> CreateScopeExit(F fn)
{
    return ScopeExit<F>(fn);
}

#define EXIT_SCOPE_CREATE_UNIQ_NAME2(line) exit_scope_guard_##line
#define EXIT_SCOPE_CREATE_UNIQ_NAME(line) EXIT_SCOPE_CREATE_UNIQ_NAME2(line)
#define EXIT_SCOPE(F) const auto  &EXIT_SCOPE_CREATE_UNIQ_NAME(__LINE__) = CreateScopeExit([]{F;})


Варианты использования:
int main()
{
    std::cout << "Outer scope enter" << std::endl;
    EXIT_SCOPE(std::cout << "Outer scope exited" << std::endl);

    {
        std::cout << "Inner scope enter" << std::endl;

        EXIT_SCOPE({std::cout << "Inner scope exited" << std::endl;});
        std::cout << "Inner scope exit" << std::endl;
    }

    std::cout << "Outer scope exit" << std::endl;
    return 0;
}
Зато безопасно. :)
Что-то мне подсказывает, что тут её и не может быть. Ну разве что в деструкторе вызов функтора обложить try-catch'ем, и не выпускать возможные исключения за пределы деструктора.
А зачем boost, если в C++11 есть std::function?
Всё зависит от того, какая политика выбирается в отношении хранения кодовой базы и инструментария, возможно ли кодогенераторы собирать вместе с регулярной сборкой продукта, сколько телодвижений придётся делать другим разработчикам, чтобы всем этим тулчейном пользоваться на рабочих машинах, и т. п.
Ну и да. Вопрос последующей поддержки. Чем большее количество языков используется в исходниках — тем большее количество разноплановых специалистов нужно, чтобы поддерживать кодовую базу. В итоге нередко получается, что знания о том, как работает ммм… скрипт для генерации ну, скажем, метаинформации по набору классов (работающий на связке doxygen + msxslt + javascript), превращаются в сакральные вместе с уходом из команды человека, который этот скрипт поддерживал.
Вопрос комфорта, на мой взгляд.
Будут, но чуть позже. Иначе статья вышла бы уж слишком большой.
Возможные области примерения, которые я вижу, две:
1. Трансляторы (кодогенераторы) C++ -> C++ типа Qt moc.
2. Лёгкие плагины к IDE, написанных на C++.

Мотивация примерно следующая. В обоих случаях основная кодовая база — на C++. Чтобы не расширять набор языков, для которых требуется поддержка (а любой скриптовый язык этот набор автоматически расширяет), «скриптование» непосредственно на C++ имело бы смысл.

Information

Rating
Does not participate
Location
Москва и Московская обл., Россия
Date of birth
Registered
Activity