У меня есть огромная библиотека музыки. И в куче файлов есть в описание силки. Я написал программку которая находит силки в описание и удаляет их. Сделал.. Но хочется добавить еще маленькую функцию. Как можно получить mime файла.
Допустим Music/Alizee - Moi... Lolita.mp3 как получить его mimetype "audio/mpeg". Сейчас я по расширению файла могу выборку файлов делать. Хочу добавить возможность и по mime делать выборку.
Detector mime
Пример использования Detector
Спасибо.
Приятно что в с++ появилось filesystem =). Я вообще удивлен что удалось очень простую задачу на С++ решить очень просто и быстро. С пол часа понадобилось чтобы сделать все что нужно. И 4 часа чтобы переделать с кучей шаблонов и constexpr=)
Появилась бы еще возможность с unicode работать без лишних телодвижений...
У меня еще один вопрос.
if constexpr (std::is_same_v<FilterCallback, DefaultArgument_t>) {
...
} else if constexpr (std::is_invocable_r_v<bool, FilterCallback, fs::path>) {
...
} else {
???
}
Можно ли остановить компиляцию и выдать ошибку если компилятор доберется до последнего else.
Не очень понятна суть вашей идеи...
Ошибки синтаксиса и Ошибки выполнения это как бы разные сущности.
Вы кого пытаетесь поймать в данном случае.
Мне кажется что Вы ловите exeption системной библиотеки и непонятно как правильно ее обработать.
Или я ошибаюсь ?
Можно ли остановить компиляцию и выдать ошибку если компилятор доберется до последнего else.
Не очень понятна суть вашей идеи...
Ошибки компиляции и ошибки выполнения это как бы две разные сущъности...
Вы что пытаетесь поймать в данном случае...
Если это Exeption системы то он и обрабатывается по своим правилам.
Ну во всех статях о С++17 приводят подобный пример использования if constexpr
В C++14 писали 2 шаблоных функции и при помощи enable_if уже уточнять когда будет вызвана функция.
// Для string
template <class T>
std::enable_if_t<std::is_same_v<std::string, T>> print(T t) {
std::cout << "String(Size: " << t.size() << ") = \"" << t << "\""
<< std::endl;
}
// Для чисел
template <class T>
std::enable_if_t<std::is_integral_v<T> || std::is_floating_point_v<T>> print(
T t) {
std::cout << "Num = " << t << std::endl;
}
С приходом C++17 появился if constexpr. Он во время компиляции отбрасывает не подходящие ветки условия. И теперь можно написать
template <class T>
void print(T t) {
if constexpr (std::is_same_v<std::string, T>) {
std::cout << "String(Size: " << t.size() << ") = \"" << t << "\""
<< std::endl;
} else if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) {
std::cout << "Num = " << t << std::endl;
} else {
}
}
Если я вызову функцию print(10), то первая ветка if будет отброшена на этапе компиляции и компилятор не будет пытаться у int искать метод size. Оба варианта будут одинаково работать если им передать string или число. Но если попытаюсь передать любой другой тип, то вариант с enable_if не будет компилироваться. А варианте с if constexpr скомпилируется и просто нечего не будет делать. А это не очень хорошо. Такое поведении мне не очень подходит. Короче я уже сам с трудом могу понять что я хочу =)
У меня в проекте есть
**
if constexpr (std::is_invocable_r_v<bool, decltype(cal), fs::path&>) {
if (cal(item) == false) break;
} else if constexpr (std::is_invocable_r_v<void, Callback,
fs::path&>) {
cal(item);
}
**
если я ошибусь и вместо колбекфункции передам розового слона... То моя функция без ошибок будет вызвана и просто нечего не сделает. Вот у меня возник вопрос. Можно ли как-то вывести ошибку и прекратить компиляцию если мы попали в else.
Этот новомодный паттерн не делался с целью обрывать компиляцию, он делался с целью менять поведение при выполнении, с небольшим бонусом в виде передачи некоторой информации компилятору.
Если вы хотите добавить в свою функцию механизм проверки допустимости типов на этапе компиляции, вы можете сделать это руками:
template <class T>
void print(T t) {
constexpr auto isInt = std::is_same<T,int>::value;
constexpr auto isFloat = std::is_floating_point<T>::value;
constexpr auto isString = std::is_same<std::string, T>::value;
static_assert(isString || isInt || isFloat); // <- тут грохнется на компиляции
if constexpr (isString) {
std::cout << "String(Size: " << t.size() << ") = \"" << t << "\""
<< std::endl;
} else if constexpr (isInt || isFloat) {
std::cout << "Num = " << t << std::endl;
} else {
}
}
просмотрел тред.
рекомендую не заморачиваться с шаблоном, а просто написать несколько отдельных функций с перегрузкой. сам решал подобную проблему несколько раз.
можно написать функции print(int) и print(string) и пользовать вызовы print(10) и print("blabla"), проще и нагляднее.
есть вариации для удобства, потом по интересу.
Просто у меня функция может принимать 2 варианта Callback функций. void(fs::path&) или bool(fs::path&). Мне кажется если использовать перегрузку... Будет очень много дублированного кода. А разница будет всего в одной строке. И если мне нужно будет что-то поправить, придется это делать в 2 вариантах функций. Шаблонная магия и if constexpr помогает чуток сэкономить. Заставить эти перегрузки генерировать сам компилятор.
ну так нет проблем использовать в шаблоне перегруженный нешаблонный print принимающий шаблонный параметр.
идея в том, чтобы написать print для какого-то конкретного типа и больше не трогать эту функцию. если нужно print-ать другой тип, пишешь еще один print, и более его не трогаешь.
в твоём же случае приходится модифицировать существующую готовую отлаженную функцию. а это в мире большого программирования не приветствуется.
но если сильно хочется через if constexpr, то ставь static_assert(false, "blabla") в ветку else
Не будет работать. Точнее, это будет прерывать компиляцию всегда.
может gcc как то особо работает, но на VS2017 без проблем
#include "stdafx.h"
#include <string>
#include <iostream>
template<typename T>
void print(T const& val)
{
if constexpr(std::is_same_v<std::string, T>)
{
std::cout << "String(Size: " << val.size() << ") = \"" << val << "\"" << std::endl;
}
else if constexpr(std::is_arithmetic_v<T>)
{
std::cout << "Num = " << val << std::endl;
}
else
{
static_assert(false, "unexpected");
}
}
int main()
{
print(10);
print(std::string("blabla"));
//print("blabla");
return 0;
}
если раскомментить строку, компиляция прервётся.
gcc и clang не компилирует
int main() {
if constexpr (true) {
} else {
static_assert(false);
}
}
VS тоже не компилирует.
но если перенести в шаблон, всё норм.
надо будет поизучать стандарт на эту тему.
https://wandbox.org/permlink/KulAMiD5LlssLSWN
Если верить сайту http://scrutator.me/post/2017/10/07/cpp17_lang_features_p2.aspx
clang и gcc поступает правильно. По стандарту выражение static_assert(false) является некорректным. А в if constexpr код должен быть корректным.
Если верить сайту https://en.cppreference.com/w/cpp/language/if ....
Можно с помощью костыля заставить работать static_assert в шаблонной функции.
#include <iostream>
#include <string>
template <class T>
struct dependent_false : std ::false_type {};
template <typename T>
void print(T const& val) {
if constexpr (std::is_same_v<std::string, T>) {
std::cout << "String(Size: " << val.size() << ") = \"" << val << "\""
<< std::endl;
} else if constexpr (std::is_arithmetic_v<T>) {
std::cout << "Num = " << val << std::endl;
} else {
static_assert(dependent_false<T>::value);
}
}
int main() {
print(10);
print(std::string("blabla"));
}
Теперь код будет нормально компилироваться.
https://wandbox.org/permlink/2uHNXRx73cSVi3vg
Рукалицооо...
Если вам так "горит" что-то засунуть в else, то засуньте static_assert из моего примера выше. С constexpr аргументом он будет полностью корректным.
Просто у меня как-то привычка сложилась: прерывающие проверки делать в начале функции, а не в заднице =)
Я не программист =). И воспользовался языком С++ чтобы автоматизировать поиск и удаления ссылок из коллекции музыки. Уверен что на bash это можно было сделать проще. Но... Я не очень люблю bash.
К сожалению я удалил уже проект. По памяти: Я хотел реализовать класс fsWalker. И у меня вышло очень не красиво.
std::enable_if_t<
(std::is_invocable_r_v<void, CallBack,fs::path&> || std::is_invocable_r_v<bool, CallBack,fs::path&>) &&
(std::is_same_v<Filter, DefaultArgument_t> || std::is_invocable_r_v<bool, Filter, fs::path>)
>
fsWalker(fs::path path, CallBack cal, Filter f) {}
int main() {
fsWalker("/home/DooM/Music/", [](fs::path& p){std::cout << p << std::endl;},defaultArgument);
fsWalker("/home/DooM/Music/", [](fs::path& p){std::cout << p << std::endl;}, FilterExtension("mp3", "m4a"));
}
Я хотел избавится от enable_if. Тема уже не актуальна =)
Отправить комментарий