Информация об изменениях

Сообщение Re[3]: Как узнать хранит ли variant... от 06.05.2025 8:30

Изменено 06.05.2025 11:24 rg45

Re[3]: Как узнать хранит ли variant...
Здравствуйте, Marty, Вы писали:

M>Ну, я хотел сделать фильтры, для преобразования выводимых строк после их форматирования, например, html/xml-escape, фильтры должны уметь передаваться как аргумент при вызове функции форматирования, наравне с самими форматируемыми величинами. А потом, внутри реализации, я решил присунуть стандартные фильтры, которые создаёт фабрика стандартных фильтров, которая задаётся параметром шаблона и возвращает такой же функтор, который может лежать в параметрах шаблона. Но конкретный тип функтора я не знаю, пользователь может не использовать мои алиасы. В аргументы стандартный фильтр я не могу запихивать, и я решил завести вектор фильтров, куда кладу либо созданный фабрикой стандартный фильтр, либо взятый из аргументов. А для этого мне надо знать тип функтора. Вот, как-то так. Пока даже что-то вырисовывается


Извини, что отвечаю с задержкой. Вот примерный эскиз. Использую концепты — просто потому что так компактнее и нагляднее, но переложить на SFINAE — это лишь дело техники.

https://coliru.stacked-crooked.com/a/29987ff10b6e141f

#include <iostream>
#include <functional>
#include <type_traits>
#include <variant>

/////////////////////////////////////////////////////////////////////////////////////////
// Вспомогательные инструменты

template <typename...T>
struct Inherited : std::decay_t<T>... {};

template <typename> struct IsFreeFunction : std::false_type{};
template<typename R, typename...A> struct IsFreeFunction<R(A...)> : std::true_type{};
template <typename T> struct IsFreeFunction<T*> : IsFreeFunction<T>{};

template <typename T>
concept FreeFunction = IsFreeFunction<std::decay_t<T>>::value;

template <typename T>
concept CallableObject =
   std::is_class_v<std::decay_t<T>>
   and not requires { &Inherited<T, decltype([]{})>::operator(); };

template <typename T>
concept Callable = FreeFunction<T> or CallableObject<T>;

template <typename T>
concept NotCallable = not Callable<T>;

template<CallableObject...T>
struct Overload : T... { using T::operator()...; };

template<CallableObject...T>
Overload(T&&...) -> Overload<std::decay_t<T>...>;

/////////////////////////////////////////////////////////////////////////////////////////
// Использование

template<typename InputIteratorType, typename OutputIteratorType>
using BasicFormatValueFilter = std::function <
   OutputIteratorType(
      InputIteratorType  // begin
   ,  InputIteratorType  // end
   ,  OutputIteratorType
   )
>;

/////////////////////////////////////////////////////////////////////////////////////////
// Является ли текущее значение варианта экземпляром функтора

template <typename...T>
auto IsCallable(const std::variant<T...>& v) {
   return std::visit(
      Overload(
         [](auto&&...) {return false;}
      ,  [](Callable auto&&) {return true;}
      )
   ,  v
   );
}

/////////////////////////////////////////////////////////////////////////////////////////
// Аналогично: есть ли что - либо на базе BasicFormatValueFilter

template <typename...T>
auto IsBasicFormatValueFilter(const std::variant<T...>& v) {
   return std::visit(
      Overload(
         [](auto&&...) {return false;}
      ,  []<typename I, typename O>(const BasicFormatValueFilter<I, O>&) {
            // А вот получить точный тип содержимого ты можешь только здесь, внутри специальной функции
            return true;
         }
      )
   ,  v
   );
}

int main()
{
   using CustomInputIterator = const int*;
   using CustomOutputIterator = double*;
   using CustomFormatValueFilter = BasicFormatValueFilter<CustomInputIterator, CustomOutputIterator>;

   using V = std::variant<int, double, CustomFormatValueFilter, std::function<double(double)>>;

   std::cout << std::boolalpha;

   std::cout << IsCallable(V{3.14}) << std::endl;                          // false
   std::cout << IsCallable(V{[](double x){return x * 10;}}) << std::endl;  // true

   std::cout << "------------------------------------------------------------------------------" << std::endl;
   auto customFilter = [](CustomInputIterator, CustomInputIterator, CustomOutputIterator) {
      return CustomOutputIterator{};
   };

   std::cout << IsBasicFormatValueFilter(V{3.14}) << std::endl;            // false
   std::cout << IsBasicFormatValueFilter(V{3.14}) << std::endl;            // false
   std::cout << IsBasicFormatValueFilter(V{customFilter}) << std::endl;    // true
}
Re[3]: Как узнать хранит ли variant...
Здравствуйте, Marty, Вы писали:

M>Ну, я хотел сделать фильтры, для преобразования выводимых строк после их форматирования, например, html/xml-escape, фильтры должны уметь передаваться как аргумент при вызове функции форматирования, наравне с самими форматируемыми величинами. А потом, внутри реализации, я решил присунуть стандартные фильтры, которые создаёт фабрика стандартных фильтров, которая задаётся параметром шаблона и возвращает такой же функтор, который может лежать в параметрах шаблона. Но конкретный тип функтора я не знаю, пользователь может не использовать мои алиасы. В аргументы стандартный фильтр я не могу запихивать, и я решил завести вектор фильтров, куда кладу либо созданный фабрикой стандартный фильтр, либо взятый из аргументов. А для этого мне надо знать тип функтора. Вот, как-то так. Пока даже что-то вырисовывается


Извини, что отвечаю с задержкой. Вот примерный эскиз. Использую концепты — просто потому что так компактнее и нагляднее. Но переложить на SFINAE — это лишь дело техники.

https://coliru.stacked-crooked.com/a/0a9e5a5ac7ee0af7

#include <iostream>
#include <functional>
#include <type_traits>
#include <variant>

/////////////////////////////////////////////////////////////////////////////////////////
// Вспомогательные инструменты

template <typename...T>
struct Inherited : std::decay_t<T>... {};

template <typename> struct IsFreeFunction : std::false_type{};
template<typename R, typename...A> struct IsFreeFunction<R(A...)> : std::true_type{};
template <typename T> struct IsFreeFunction<T*> : IsFreeFunction<T>{};

template <typename T>
concept FreeFunction = IsFreeFunction<std::decay_t<T>>::value;

template <typename T>
concept CallableObject =
   std::is_class_v<std::decay_t<T>>
   and not requires { &Inherited<T, decltype([]{})>::operator(); };

template <typename T>
concept Callable = FreeFunction<T> or CallableObject<T>;

template<CallableObject...T>
struct Overload : T... { using T::operator()...; };

template<CallableObject...T>
Overload(T&&...) -> Overload<std::decay_t<T>...>;

/////////////////////////////////////////////////////////////////////////////////////////
// Использование

template<typename InputIteratorType, typename OutputIteratorType>
using BasicFormatValueFilter = std::function <
   OutputIteratorType(
      InputIteratorType  // begin
   ,  InputIteratorType  // end
   ,  OutputIteratorType
   )
>;

/////////////////////////////////////////////////////////////////////////////////////////
// Является ли текущее значение варианта экземпляром функтора

template <typename...T>
bool IsCallable(const std::variant<T...>& v) {
   return std::visit(
      Overload(
         [](auto&&...) {return false;}
      ,  [](Callable auto&&) {return true;}
      )
   ,  v
   );
}

/////////////////////////////////////////////////////////////////////////////////////////
// Аналогично: есть ли что - либо на базе BasicFormatValueFilter

template <typename...T>
bool IsBasicFormatValueFilter(const std::variant<T...>& v) {
   return std::visit(
      Overload(
         [](auto&&...) {return false;}
      ,  []<typename I, typename O>(const BasicFormatValueFilter<I, O>&) {
            // А вот получить точный тип содержимого ты можешь только здесь, внутри специальной функции
            return true;
         }
      )
   ,  v
   );
}

int main()
{
   using CustomInputIterator = const int*;
   using CustomOutputIterator = double*;
   using CustomFormatValueFilter = BasicFormatValueFilter<CustomInputIterator, CustomOutputIterator>;

   using V = std::variant<int, double, CustomFormatValueFilter, std::function<double(double)>>;

   std::cout << std::boolalpha;

   std::cout << IsCallable(V{3.14}) << std::endl;                          // false
   std::cout << IsCallable(V{[](double x){return x * 10;}}) << std::endl;  // true

   std::cout << "--" << std::endl;
   auto customFilter = [](CustomInputIterator, CustomInputIterator, CustomOutputIterator) {
      return CustomOutputIterator{};
   };

   std::cout << IsBasicFormatValueFilter(V{3.14}) << std::endl;            // false
   std::cout << IsBasicFormatValueFilter(V{3.14}) << std::endl;            // false
   std::cout << IsBasicFormatValueFilter(V{customFilter}) << std::endl;    // true
}