Как сделать так, чтобы std::filesystem соответствовала стандартам Visual Studio 2015?

У меня есть проект, который в настоящее время заблокирован в Visual Studio 2015. Однако я хочу написать код, максимально соответствующий стандартам.

Я хочу использовать std::filesystem но это не вошло в стандарт до C++-17. К счастью, почти все доступно, только в std::experimental::filesystem::v1 Пространство имен. Я не фанат одеял using директивы; Я предпочитаю полностью охватывать вещи, чтобы было ясно, откуда они берутся. Так что я не собираюсь просто положить в глобальный using заявление. Требуется какое-то волшебство, чтобы убедить компилятор сделать то, что я хочу.

Это была моя первая попытка:

#include <filesystem>
#if defined(_MSC_VER) && _MSC_VER <= 1900 // VS 2015
namespace std {
    namespace filesystem {
        using path = std::experimental::filesystem::v1::path;
    }
}
#endif

Это работает довольно хорошо, и std::filesystem::path теперь доступно. Я тестировал создание и использование path объекты и это работает.

По мере продвижения вперед я знаю, что мне понадобится больше вещей. Я задавался вопросом, может ли быть способ просто внести все это:

namespace std {
    namespace filesystem {
        using std::experimental::filesystem::v1;
    }
}

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

Далее я хочу получить directory_entry, Кажется, работает та же техника

namespace std {
    namespace filesystem {
        using directory_entry = std::experimental::filesystem::v1::directory_entry;
    }
}

Опять же, компилятор выглядит счастливым.

Теперь я хочу использовать std::directory::create_directories, Однако это функция, а не класс, поэтому тот же метод не сработает.

я думал так std::function может быть специально для этого, но мне не повезло. Я старался

namespace std {
    namespace filesystem {
        function<bool(path)> create_directories = std::experimental::filesystem::v1::create_directories;
    }
}

и компилятор говорит

Error   C2440   'initializing': cannot convert from 'overloaded-function' to 'std::function<bool (std::filesystem::path)>'

Есть две перегрузки функции (одна принимает второй аргумент, чтобы вернуть код ошибки, а не выдавать исключение).

Я застрял. Это должно быть возможно, но мой C++-foo слабый.

1 ответ

Ответ лежит в сообщении об ошибке, и помощь, необходимая для создания экземпляра std::function для перегруженного метода. Спасибо MFisherKDX за указание на меня здесь и W.F. за ответ, который работает.

Игнорируя вопрос о том, является ли законным, моральным или хорошим вкусом расширение стандартного пространства имен (потому что в этом случае я считаю, что это как минимум 2 из 3), вот мой полностью прокомментированный обходной путь:

#if defined(_MSC_VER) && _MSC_VER <= 1900
// Visual Studio 2015 work-around ... 
// std::filesystem was incorporated into C++-17 (which is obviously after VS
// 2015 was released). However, Microsoft implemented the draft standard in
// the std::exerimental namespace. To avoid nasty ripple effects when the
// compiler is updated, make it look like the standard here
#include <functional>
namespace std {
  namespace filesystem {
    using directory_entry = std::experimental::filesystem::v1::directory_entry;
    using directory_iterator = std::experimental::filesystem::v1::directory_iterator;
    function<bool(path const&)> create_directories = 
        static_cast<bool(*)(path const&)>(
            std::experimental::filesystem::v1::create_directories);
  }
}
#endif

ОБНОВЛЕНИЕ: у Sebastian Redl было самое простое решение.

#if defined(_MSC_VER) && _MSC_VER <= 1900
// Visual Studio 2015 work-around ... 
// std::filesystem was incorporated into C++-17 (which is obviously after VS
// 2015 was released). However, Microsoft implemented the draft standard in
// the std::exerimental namespace. To avoid nasty ripple effects when the
// compiler is updated, make it look like the standard here
namespace std {
  namespace filesystem = experimental::filesystem::v1;
}
#endif

Кстати, для gcc 7.3 требуется почти такой же обходной путь, кроме случаев, когда вы не можете

#include <filesystem>

но должен

#include <experimental/filesystem>

вместо

Другие вопросы по тегам