Russian Qt Forum

Qt => Кладовая готовых решений => Тема начата: navrocky от Февраль 11, 2015, 13:18



Название: (С++11) Variant - простой аналог boost::any
Отправлено: navrocky от Февраль 11, 2015, 13:18
Предлагаю вашему вниманию простой аналог boost::any. Иногда случается, что QVariant неудобен или проект не основан на Qt, а boost тащить не особо хочется.

В моём случае это был C++ проект под мобилку. Простых и понятных реализаций я навскидку не нашел, поэтому свелосипедил свою.

Пример использования:
Код
C++ (Qt)
Variant v;
v = 10;
if (v.isType<int>())
   cout << v.value<int>() << endl;

Плюсы:
  • всё реализовано в одном заголовочном файле
  • поддерживается сравнение по значению, если сравнение поддерживается хранимым типом
  • зависит только от стандартной библиотеки C++ 11

Минусы:
  • зависит от RTTI
  • использует динамическую память под хранение значения
  • C++03 не поддерживается

По умолчанию при кастовании происходит сравнение строк с названиями типов хранимых значений. Можно включить оптимизацию -DVARIANT_CAST_OPTIMIZATION=1, которая приведет к сравнению типов по указателю, но при этом теряется возможность использовать Variant в интерфейсе динамических библиотек (т.к. таблицы метаданных разные).

Актуальный исходник здесь: https://github.com/navrocky/Variant


Название: Re: Простой аналог boost::any
Отправлено: panAlexey от Февраль 11, 2015, 16:57
Спасибо!


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: vregess от Февраль 11, 2015, 20:57
А еще есть cdiggins::any (http://www.codeproject.com/Articles/11250/High-Performance-Dynamic-Typing-in-C-using-a-Repla)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 12, 2015, 12:15
А можно ли оперировать выражениями, было бы круто напр
Код
C++ (Qt)
Variant a, b, c;
..
Variant result = (a > 0) ? b : c;
Или это неизбежно сваливается в дебри свитчей?


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: navrocky от Февраль 12, 2015, 16:36
А можно ли оперировать выражениями

Технически такое сделать вполне возможно. Только сравнивать можно одинаковые типы. Не прокатит конвертация.. Хотя если запилить аналог lexical_cast, то на его базе можно и сравнение разных типов сделать.   Сейчас пробую.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 12, 2015, 17:43
У меня пара комментариев по реализации:

1) Всё же, сравнение типов как строк (и их хранение в HolderBase) не очень оптимальное решение.. Почему бы вместо этого не использовать std::dynamic_pointer_cast в методе isType():
Код
C++ (Qt)
template <typename T>
   bool isType() const
   {
       return std::dynamic_pointer_cast<Holder<T>>(holder_) != 0;
   }
 
 
Не вижу к каким проблемам это может привести?

2) Наверное логичнее/нагляднее кидать std::bad_cast вместо std::runtime_error?
Код
C++ (Qt)
template <typename T>
   const T& value() const throw (std::bad_cast)
   {
       if (!isType<T>())
           throw std::bad_cast();
       return std::static_pointer_cast<Holder<T>>(holder_)->value;
   }
 



Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: navrocky от Февраль 12, 2015, 19:00
1) Всё же, сравнение типов как строк (и их хранение в HolderBase) не очень оптимальное решение.. Почему бы вместо этого не использовать std::dynamic_pointer_cast в методе isType():
Не вижу к каким проблемам это может привести?

dynamic_cast не работает в динамических библиотеках. Соответственно если либа выдаст вам такой Variant, в основном коде уже ничего не сможете из него вытащить. Хотя согласен, что сравнение указателя эффективнее чем сравнение строки.
Может быть сделать эту оптимизацию через DEFINE?

Кстати сейчас вспомнил, что реализация dynamic_cast в студийном компиляторе сравнивает строки.

2) Наверное логичнее/нагляднее кидать std::bad_cast вместо std::runtime_error?

С этим согласен, подправлю.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: navrocky от Февраль 12, 2015, 19:16
Выхожил код на GitHub, чтобы легче было дописывать. ссылку положил в шапку.

  • по просьбе Igors добавил возможность сравнивать Variant, теперь их можно размещать в std::map и прочие упорядоченные контейнеры
  • также добавил возможность включения оптимизации кастования, которая сравнивает только указатели
  • добавил тесты


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 12, 2015, 19:46
Цитировать
dynamic_cast не работает в динамических библиотеках. Соответственно если либа выдаст вам такой Variant, в основном коде уже ничего не сможете из него вытащить.
Да, погуглил сейчас на эту тему.. Как я понял, это особенность реализации rtti..

Однако, накидал тестовый пример, где у меня (gcc 4.8.2) всё работает.. (аттач)
Или я что то неправильно понял?





Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 12, 2015, 20:00
Цитировать
по просьбе Igors добавил возможность сравнивать Variant, теперь их можно размещать в std::map и прочие упорядоченные контейнеры
Имхо, плохая идея.. Я бы не стал раздувать из variant супер-класс с операторами сравнения и т.д..
Завтра igorsу приспичит не только сравнивать но и складывать, умножать, инкрементировать/декрементировать  и т.д.. И что же? Во что ваш variant превратиться?) 


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Bepec от Февраль 12, 2015, 23:34
в буст :D


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: vbv от Февраль 13, 2015, 02:10
А взять и сделать вытяжку из boost только его(boost::any) одного и использовать (хоть статически хоть динамически), не плодя велосипеды?
Не, если задача чисто академическая... Тогда успехов.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: navrocky от Февраль 13, 2015, 10:17
А взять и сделать вытяжку из boost только его(boost::any) одного и использовать (хоть статически хоть динамически), не плодя велосипеды?
Не, если задача чисто академическая... Тогда успехов.
Я об этом думал, но глядя на запутанные исходники мне становилось грустно.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: navrocky от Февраль 13, 2015, 10:33
Однако, накидал тестовый пример, где у меня (gcc 4.8.2) всё работает.. (аттач)
Или я что то неправильно понял?
Да, действительно. Надо бы поглядеть реализацию на асме...


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 13, 2015, 12:25
Код
C++ (Qt)
template <typename Type>
struct HasEqualOperator
{
typedef char yes[1];
typedef char no[2];
template <std::size_t N>
struct SFINAE {};
template <typename T>
static yes& isEqualComparable(SFINAE<sizeof(*static_cast<T*>(0) == *static_cast<T*>(0))>* = 0);
 
Оказывается уже и так можно! (заглянул в справочник :)). Однако, если я правильно понял, экземпляр типа может сравниваться только с точно таким же (напр сравнение float с double поведет к runtime error).

Я не сторонник таких вещей. "Секрет успеха С++ в его совместимости с С". Переменная int - это 4 байта в памяти - и ВСЕ, никаких доп данных нет. Это нормально и хорошо. Но энтузиастам неймется, поэтому начинается выкручивание рук с гребаными темплейтами. Т.е. вообще-то тип не хранится, но когда объявляем переменную - компилятор его знает, вот на этом будем что-то варить... На мой взгляд это попытки придать языку нечто несвойственное, не лучше ли выскочить в тот же Пытон где все это натурально.

Однако привлекает простота с которой Вы это сбацали. Хранить в контейнере "всякую всячину" - реально usable. По поводу развития этого мини-проекта: лучше оставить его "lite", не пытаться накручивать операторов и.т.п. - по-моему это оказалось неудачным, потерялась "легкость".  Вместо этого организовать хранение простых типов (до 8 байт) "на месте" вместо кучи, а то сейчас реализация "жирная"

Спасибо



Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: navrocky от Февраль 13, 2015, 13:08
По поводу оператора ==, он однозначно нужен, чтобы можно было делать find. И его результат интерпретируется однозначно.

А вот по операторам сравнения не всё однозначно, я сейчас не могу вспомнить годный пример, помню только одно, что оно мне когда-то было нужно и я гуглил как это сделать с boost::any.. Может быть я тогда был не прав, не помню. Может быть стоит их выкинуть, чтобы никого не смущать?


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 13, 2015, 14:25
По поводу оператора ==, он однозначно нужен, чтобы можно было делать find. И его результат интерпретируется однозначно.

А вот по операторам сравнения не всё однозначно, я сейчас не могу вспомнить годный пример, помню только одно, что оно мне когда-то было нужно и я гуглил как это сделать с boost::any.. Может быть я тогда был не прав, не помню. Может быть стоит их выкинуть, чтобы никого не смущать?
Тоже мне ценность "find". И насчет однозначности неясно (5 == 5.0  ???). Может неплохо бы иметь

bool isNumeric()
bool isPointer()
double toDouble()
void * toPointer()

А операторы/сортировки проще накрутить на стороне юзера


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: navrocky от Февраль 13, 2015, 16:59
Ну ладно, кому что.. Оставляю в том виде как есть, больше не наворачиваю.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 13, 2015, 18:25
Раз уж такое дело, приведу (чисто в академических целях) простенькую реализацию аналога boost::variant (не путать с boost::any)
Меташаблонная магия позволяет в этом случае полностью избавиться от RTTI, но взамен, при объявлении variantа нужно передать ему список тех типов с которыми он может работать, т.е:

Код
C++ (Qt)
variant<int, double, std::string> v = 10;
 
if (v.is_type<int>())
   std::cout << v.get<int>() << std::endl;
 
v = 0.5;
std::cout << v.get<double>() << std::endl;
 
v = std::string("hello-hello");
std::cout << v.get<std::string>() << std::endl;
 
 



Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: navrocky от Февраль 13, 2015, 23:36
Раз уж такое дело, приведу (чисто в академических целях) простенькую реализацию аналога boost::variant (не путать с boost::any)
Меташаблонная магия позволяет в этом случае полностью избавиться от RTTI, но взамен, при объявлении variantа нужно передать ему список тех типов с которыми он может работать.

_id можно запихнуть в holder, всё же меньше копироваться будет )

Я так понимаю недопустимость типа тоже контролируется, т.е. запихнуть можно только тип из списка?

Можно назвать для большего понимания limited_variant или как-то так. Всё время меня смущало, что в бусте variant не variant в обычном понимании.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 14, 2015, 00:00
Цитировать
_id можно запихнуть в holder, всё же меньше копироваться будет )
Согласен)

Цитировать
Я так понимаю недопустимость типа тоже контролируется, т.е. запихнуть можно только тип из списка?
Да, тип только из доступных из списка. Это безопасно)

Цитировать
Можно назвать для большего понимания limited_variant или как-то так. Всё время меня смущало, что в бусте variant не variant в обычном понимании.
Можно, конечно.. Но я это уж так, не для пользования, а скорее ради обсуждения концепта) Т.е. если мне мне будет нужно, то я буду пользовать boost, конечно)



Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 14, 2015, 00:19
Цитировать
Но я это уж так, не для пользования, а скорее ради обсуждения концепта)
Кстатии, к слову о концепте)
Недавно здесь поднималась тема про свич и иже с ним, где я упомянул о static_visitor.. Так вот, в этой доморощенной реализации variant можно также реализовать нечто подобное визитёру.
Т.е. если у нас есть контейнер с вариантами и нужно его как то обработать без if-else-свичей то как вариант это можно сделать так:

Код
C++ (Qt)
#include <iostream>
#include <list>
#include <variant.h>
 
 
typedef variant<int, double, std::string> my_variant;
 
void print_int(const my_variant & v)
{
   std::cout << " int " << v.get<int>() << std::endl;
}
 
void print_double(const my_variant & v)
{
   std::cout << " double " << v.get<double>() << std::endl;
}
 
void print_str(const my_variant & v)
{
   std::cout << " str " << v.get<std::string>() << std::endl;
}
 
int main()
{
   std::list<my_variant> list;
   list.push_back(10);
   list.push_back(0.5);
   list.push_back(std::string("hello-hello"));
 
 
   variant_visitor<int, double, std::string> my_visitor;
 
   my_visitor.reg<int>(&print_int);
   my_visitor.reg<double>(&print_double);
   my_visitor.reg<std::string>(&print_str);
 
   for (auto v : list)
       my_visitor(v);
 
   return 0;
}
 
 
 

Код
Bash
int 10
double 0.5
str hello-hello
 




Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 14, 2015, 09:47
Т.е. если у нас есть контейнер с вариантами и нужно его как то обработать без if-else-свичей то как вариант это можно сделать так:
Код
C++ (Qt)
   my_visitor.reg<int>(&print_int);
   my_visitor.reg<double>(&print_double);
   my_visitor.reg<std::string>(&print_str);
 
 
Ну switch все же куда приятнее чем N "псевдо-классов"  :)

Эх, если бы это темплейт-усердие применить для реального дела, алгоритмов - вот было бы здорово! Но увы  :'(


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 14, 2015, 12:04
Эх, если бы это темплейт-усердие применить для реального дела, алгоритмов - вот было бы здорово! Но увы  :'(
Да, финдреплейсов можно было бы написать море, а сколько огромных свитчей можно было расширить на еще одно действие.... :)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 14, 2015, 12:18
Эх, если бы это темплейт-усердие применить для реального дела, алгоритмов - вот было бы здорово! Но увы  :'(
Да, финдреплейсов можно было бы написать море, а сколько огромных свитчей можно было расширить на еще одно действие.... :)


Непочатый край работы) Что ещё нужно для счастья творческой личности :)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 14, 2015, 13:13
Ой-ой :) Не, ну конечно так бы я не написал (не додумался бы), но вот чисто с утилитарной, прямо-таки "шкурной" точки зрения - а что, собственно, достигнуто? Еще одна остроумная поделка. А для чего? И как с нее снять бабло?..... Ну вот, сами же видите - никак. Может тлеет надежда "показать себя крутым" (чтобы больше платили) - так это напрасно  :)

Ладно, тут у меня задумка мини-проект сделать и выложить, вот только немного освобожусь...


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 14, 2015, 13:16
Ой-ой :) Не, ну конечно так бы я не написал (не додумался бы), но вот чисто с утилитарной, прямо-таки "шкурной" точки зрения - а что, собственно, достигнуто? Еще одна остроумная поделка. А для чего? И как с нее снять бабло?.....
А со свитча вы как бабло снимаете, а с фора? :)

Может тлеет надежда "показать себя крутым" (чтобы больше платили) - так это напрасно  :)
Ах эти комплексы. :)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 15, 2015, 13:52
 
Ой-ой :) Не, ну конечно так бы я не написал (не додумался бы), но вот чисто с утилитарной, прямо-таки "шкурной" точки зрения - а что, собственно, достигнуто? Еще одна остроумная поделка. А для чего? И как с нее снять бабло?..... Ну вот, сами же видите - никак. Может тлеет надежда "показать себя крутым" (чтобы больше платили) - так это напрасно  :)

Океюшки, вот простой типичный пример: Имеется контейнер вариантов, для различных представлений чисел, например (double, int, std::string).
Мы хотим иметь возможность сортировать его.. (самая типичная ситуация)
С патерном визитёра это делается в пару строк:
Код
C++ (Qt)
#include <iostream>
#include <list>
#include <variant.h>
#include <string>
 
 
typedef variant<int, double, std::string> variant_t;
 
int main()
{
   std::list<variant_t> list;
   list.push_back(std::string("-42.45938"));  // string
   list.push_back(0.5);                                  // double
   list.push_back(std::string("2.34"));         // string
   list.push_back(3.565);                            // double
   list.push_back(10);                                // int
 
 
   variant_visitor<double (variant_t)> my_visitor;
 
   my_visitor.reg<int>([](variant_t v) { return v.get<int>(); } );
   my_visitor.reg<double>([](variant_t v) { return v.get<double>(); } );
   my_visitor.reg<std::string>([](variant_t v) { return std::stod(v.get<std::string>()); } );
 
   for (auto v : list)
       std::cout << my_visitor(v) << std::endl;
 
   list.sort([&](variant_t v1, variant_t v2) { return my_visitor(v1) > my_visitor(v2); });
 
   std::cout << "--------------------------------" << std::endl;
 
   for (auto v : list)
       std::cout << my_visitor(v) << std::endl;
 
 
   return 0;
}
 

Причём, мы имеем полную типобезопасность)

Мне вот интересно, как Вы аналогичное будете реализовывать с Вашим милым и родным свитчем? 

P.S. Проект приаттачен..

PPS Надеюсь, комрад  navrovsky с пониманием отнесётся к тому, что мы тут паразитируем на его теме)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 15, 2015, 15:04
Причём, мы имеем полную типобезопасность)
"типо" может и имеете, но вот ошибки не контролируете, напр string("abc")

Мне вот интересно, как Вы аналогичное будете реализовывать с Вашим милым и родным свитчем? 
Да хотя бы так
Код
C++ (Qt)
bool IsLess( const Variant & v1, const Variant & v2 )
{
double d1, d2;
bool num1 = TryConvert2Double(v1, &d1);
bool num2 = TryConvert2Double(v2, &d2);
if (num1 && num2)
 return d1 < d2;
return num1 && !num2;
}


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 15, 2015, 15:15
Цитировать
"типо" может и имеете, но вот ошибки не контролируете, напр string("abc")
Для иллюстрации данного примера это не принципиально..


Цитировать
Да хотя бы так
Чтож Вы самое интересное то не показали?
Можно под капот TryConvert2Double посмотреть?)




Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 15, 2015, 16:04
Для иллюстрации данного примера это не принципиально..
А мне кажется - очень принципиально, именно такие "мелочи" хоронят вумный (или за-умный) код  :)

Чтож Вы самое интересное то не показали?
Можно под капот TryConvert2Double посмотреть?)
Ну а чего ж нельзя?  :)
Код
C++ (Qt)
bool TryConvert2Double( const Variant & v, double * result = 0 )
{
if (v.is_type<int>()) {
 if (result) *result = v.get<int> ();
 return true;
}
 
if (v.is_type<double>()) {
 if (result) *result = v.get<double> ();
 return true;
}
 
if (v.is_type<std::string>())
 return TryStr2Double(v.get <std::string> (), &result);
 
return false;
}


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 15, 2015, 18:52
А мне кажется - очень принципиально, именно такие "мелочи" хоронят вумный (или за-умный) код   :)
Ну хорошо:
Код
C++ (Qt)
list.sort([&](variant_t v1, variant_t v2)->bool
   {
       try {
           return my_visitor(v1) > my_visitor(v2);
       } catch (...) {
           return false;
       }
   });
 

Ну а чего ж нельзя?  :)
Код
C++ (Qt)
bool TryConvert2Double( const Variant & v, double * result = 0 )
{
if (v.is_type<int>()) {
 if (result) *result = v.get<int> ();
 return true;
}
 
if (v.is_type<double>()) {
 if (result) *result = v.get<double> ();
 return true;
}
 
if (v.is_type<std::string>())
 return TryStr2Double(v.get <std::string> (), &result);
 
return false;
}
А, ну теперь понятно на чём и как Вы бабло снимаете..  :)



Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 15, 2015, 18:58
А, ну теперь понятно на чём и как Вы бабло снимаете..  :)
А будет в варианте 10 возможных типов, будем для каждого значения проверять все десять типов. А при сортировке, так и по многу раз. Сойдет. :)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 16, 2015, 12:32
Ну хорошо:
Код
C++ (Qt)
list.sort([&](variant_t v1, variant_t v2)->bool
   {
       try {
           return my_visitor(v1) > my_visitor(v2);
       } catch (...) {
           return false;
       }
   });
 
Такая сортировка "нетранзитивна", о чем мы с Вами, батенька, уже не раз говорили. В том-то и дело что "просто отпихнуться" в Вашей схеме не удается

А будет в варианте 10 возможных типов, будем для каждого значения проверять все десять типов.
Да, будем, причем и Вы тоже  :)

А при сортировке, так и по многу раз. Сойдет. :)
Именно так. Не надо усложнять и накручивать пока это не вызывается необходимостью.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: panAlexey от Февраль 16, 2015, 17:20
Код
C++ (Qt)
list.sort([&](variant_t v1, variant_t v2)->bool
 
Че это за синтаксис такой? О_о...


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 16, 2015, 19:09
Да, будем, причем и Вы тоже  :)
Не, мы не будем. Мы можем вызывать нужную функцию для каждого типа.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 16, 2015, 20:29
Цитировать
Такая сортировка "нетранзитивна", о чем мы с Вами, батенька, уже не раз говорили. В том-то и дело что "просто отпихнуться" в Вашей схеме не удается
От чего отпихнуться? От длинных простыней с ifами на каждый тип во всех функциях? Суть обсуждаемого вопроса здесь именно в этом и состоит - нужно отпихнуться от этого..
А  транзитивность/нетранзитивность сортировки это уже нужно рассматривать в контексте конкретной задачи, например контролировать значения при формировании самого списка или.. ) 

Код
C++ (Qt)
list.sort([&](variant_t v1, variant_t v2)->bool
 
Че это за синтаксис такой? О_о...
O__o Лямбда же..)
  


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Авварон от Февраль 17, 2015, 10:13
Посмотрите как QVariant::operator< сделан


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 17, 2015, 10:40
А  транзитивность/нетранзитивность сортировки это уже нужно рассматривать в контексте конкретной задачи, например контролировать значения при формировании самого списка или.. ) 
Хорошо, говорю прямым текстом: Ваш функтор сортировки неверен. Пример (контейнеры вариантов)
Цитировать
{ 1, "abc" }
{ "abc", 1 }
Здесь ваш оператор < везде вернет false, как бы "все элементы равны". Для стандартного quicksort "сортированные" массивы и останутся такими же. Что это за сортировка если рез-т зависит от порядка исходных данных?

От чего отпихнуться? От длинных простыней с ifами на каждый тип во всех функциях? Суть обсуждаемого вопроса здесь именно в этом и состоит - нужно отпихнуться от этого..
"Удирая от пуделя Вы попадаете в лапы льва". Да, Вы несколько сократили текст и отбили десяток строк. Но ценой его усложнения, и теперь решить маленькую проблемку "некорректная строка" оказывается не так уж просто даже для автора красивой конструкции. А если писали не Вы, и нужно какое-то время чтобы вжиться в чужой код - поверьте, это несладко. В то же время лобовой код (тупой, убогий, примитивный - как хотите) не имеет с этим никаких проблем и понятен любому за минуты.

Ну хорошо, а если действительно там типов "много", напр не только int и double, но и char, short, long, float, signed/unsigned и.т.п. Здесь я бы постарался сделать "классы" (категории) вариантов, напр "числовой", "строковый", "указатель" и "кастом" - ну может что-то еще, но получается немного. Это покрыло бы большинство потребностей (пусть не все). Как это сделать с помощью "шаблонной магии" - не знаю, с удовольствием послушаю. Напр такое
Код
C++ (Qt)
if (v.IsNumeric())   // реально ли это без перебора?
double d = v.GetVal <double> ();
Спасибо


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 17, 2015, 12:08
Цитировать
Здесь ваш оператор < везде вернет false, как бы "все элементы равны". Для стандартного quicksort "сортированные" массивы и останутся такими же. Что это за сортировка если рез-т зависит от порядка исходных данных?
Правильно, поскольку сортировка для такого списка теряет смысл.. О чём я и говорил..

Цитировать
Ну хорошо, а если действительно там типов "много", напр не только int и double, но и char, short, long, float, signed/unsigned и.т.п. Здесь я бы постарался сделать "классы" (категории) вариантов, напр "числовой", "строковый", "указатель" и "кастом" - ну может что-то еще, но получается немного. Это покрыло бы большинство потребностей (пусть не все). Как это сделать с помощью "шаблонной магии" - не знаю, с удовольствием послушаю. Напр такое
Вот это как раз можно легко реализовать.. и boost::variant для этого всё предоставляет. Как? напишу чуть позже.. Сейчас бежать надо..) 


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 17, 2015, 12:34
Правильно, поскольку сортировка для такого списка теряет смысл.. О чём я и говорил..
и должна быть максимально быстро прервана, например, исключением.
А уж если решили "сортировать" строки, которые однозначно не могут быть преобразованы в число, то  нужно сразу определиться и считать такие элементы равными нулю или -100500.
Все это легко укладывается в решение с визитерами без детского перебором всех типов стопитсот раз.

Как? напишу чуть позже..
Как снимать с этого бабло? :)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: navrocky от Февраль 17, 2015, 13:10
Посмотрите как QVariant::operator< сделан

Во, кстати, в Qt5 добавили относительное сравнение в QVariant. Видимо смысл всё-таки какой-то в этом есть. Значит выкидывать у себя точно не буду :)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 17, 2015, 13:15
Во, кстати, в Qt5 добавили относительное сравнение в QVariant. Видимо смысл всё-таки какой-то в этом есть. Значит выкидывать у себя точно не буду :)
Все таки any это не variant, IMHO.
Это больше хранилище для "всего". :)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 17, 2015, 13:27
Правильно, поскольку сортировка для такого списка теряет смысл.. О чём я и говорил..
и должна быть максимально быстро прервана, например, исключением.
Во как - "теряет смысл". Сначала мы заявляем что наш вариант хранит что угодно, а теперь работаем "только с тем что можно", а иначе - любимое исключение, и разбирайтесь как хотите (хз как). Куда же делись все "концепты"?

А уж если решили "сортировать" строки, которые однозначно не могут быть преобразованы в число, то  нужно сразу определиться и считать такие элементы равными нулю или -100500.
Все это легко укладывается в решение с визитерами без детского перебором всех типов стопитсот раз.
Ну тогда уже -inf, хотя в любом случае это заплатка которая ни на какую концептуальность не претендует. И в чем кайф решения с визиторами? Чем оно принципиально лучше того же перебора? Если нужно поддерживать еще один тип, напр float - появляется еще один визитор. А в рамках др задачи - опять их все рисовать. Правильно я пониманию?

Зато что действительно достигнуто - куча понтов. Говоришь такому - неправильно сортирует, вылетает, исправь. Не тут-то было. Оно вступает в пререкания, начинает доказывать что это делать не нужно, упирается, в конце-концов, может быть, "сделает одолжение". Поверьте, его остроумные (иногда) решения отнюдь не компенсируют головной боли с ним.

Да, и вот
Посмотрите как QVariant::operator< сделан
По существу - перебором. Ну с некоторыми улучшениями, напр ID числовых типов собраны в одном диапазоне, поэтому быстрая проверка на canConvert и.т.п. Но это непринципиально


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 17, 2015, 13:45
Во как - "теряет смысл". Сначала мы заявляем что наш вариант хранит что угодно, а теперь работаем "только с тем что можно", а иначе - любимое исключение, и разбирайтесь как хотите (хз как). Куда же делись все "концепты"?
А при чем здесь концепты и не валидные для сортировки данные?
Как можно сортировать совместно числа и строки? Что больше 123 или "abc"?
Сообщите эти правила и я легко изменю функцию преобразования строки под ваши правила. Одну функцию исключительно для строки.

Ну тогда уже -inf
Да хоть -1. Это все ничего не значащие частности, которым вы пытаетесь придать огромное значение. :)

хотя в любом случае это заплатка которая ни на какую концептуальность не претендует.
Конечно заплатка, вы не контролируете входные данные, в коллекцию "всего" набиваете "все", потом хотите это сортировать... В таком подходе без заплаток никуда.

И в чем кайф решения с визиторами? Чем оно принципиально лучше того же перебора?
Тем что в нем нет этого самого тупого перебора выполняющегося огромное число раз.

Если нужно поддерживать еще один тип, напр float - появляется еще один визитор.
Нет, визитер останется один.

Зато что действительно достигнуто - куча понтов. Говоришь такому - неправильно сортирует, вылетает, исправь. Не тут-то было.
А это не возможно исправить без допущений, а с допущением делается легко и не принужденно и не убивает все ресурсы процессора на перебор типов.
Ваше сравнение точно также использует допущения, как только один из элементов не число.
Повторюсь, формулируйте правила преобразования не числа в число и это легко можно реализовать.

Оно вступает в пререкания, начинает доказывать что это делать не нужно, упирается, в конце-концов, может быть, "сделает одолжение". Поверьте, его остроумные (иногда) решения отнюдь не компенсируют головной боли с ним.
Что-то вы расфантазировались под конец... :)
Осторожненько, не подеритесь с этим. :)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 17, 2015, 16:29
Цитировать
Вот это как раз можно легко реализовать.. и boost::variant для этого всё предоставляет. Как?
Это можно реализовать так:

Код
C++ (Qt)
#include <iostream>
#include <boost/variant.hpp>
 
 
template <class T>
struct numeric_visitor : public boost::static_visitor<T>
{
   T operator()(int val) const { return val; }
 
   T operator()(float val) const { return val; }
 
   T operator()(double val) const { return val; }
 
   template <class S>
   T operator()(S) const { return T(); } // или кидаем исключение..
};
 
template <class T>
struct string_visitor : public boost::static_visitor<T>
{
   T operator()(const std::string& val) const { return val; }
 
   template <class S>
   T operator()(S) const { return T(); } // или кидаем исключение
};
 
 
struct numeric_category : public boost::static_visitor<bool>
{
   bool operator()(double) const { return true; }
   bool operator()(float) const { return true; }
   bool operator()(int) const { return true; }
 
   template <class T>
   bool operator()(T) const { return false; }
 
};
 
struct string_category : public boost::static_visitor<bool>
{
   bool operator()(std::string) const { return true; }
 
   template <class T>
   bool operator()(T) const { return false; }
};
 
 
template <class V>
bool is_numeric(V v)
{
   return boost::apply_visitor(numeric_category(), v);
}
 
template <class V>
bool is_string(V v)
{
   return boost::apply_visitor(string_category(), v);
}
 
 
int main()
{
   typedef boost::variant<double, float, int, std::string> variant_t;
 
   variant_t v1 = 1.1234; // 10; 1.234f ...
   variant_t v2 = std::string("abc");
 
   if (is_numeric(v1))
       std::cout << "numeric: val = " << boost::apply_visitor(numeric_visitor<double>(), v1) << std::endl;
 
   if (is_string(v2))
       std::cout << "string: val = " << boost::apply_visitor(string_visitor<std::string>(), v2) << std::endl;
 
   return 0;
}
 

Цитировать
Как снимать с этого бабло?  :)
Ну для человека у которого есть талант снимать бабло с if-else-switch простыней, то это даже не вопрос  :) 


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 17, 2015, 21:22
Хм.. можно сделать ещё лаконичнее и проще, используя boost::optional
Пример с самодельным вариантом:

Код
C++ (Qt)
#include <iostream>
#include <variant.h>
#include <string>
#include <boost/optional.hpp>
 
typedef variant<float, double, int, std::string> variant_t;
 
int main()
{
   variant_visitor<boost::optional<double> (variant_t)> is_numeric;
   is_numeric.reg<double>([](variant_t v) { return v.get<double>(); });
   is_numeric.reg<int>([](variant_t v) { return v.get<int>(); });
   is_numeric.reg<float>([](variant_t v) { return v.get<float>(); });
 
   variant_visitor<boost::optional<std::string> (variant_t)> is_string;
   is_string.reg<std::string>([](variant_t v) { return v.get<std::string>(); });
 
   variant_t v = 123.676;
   variant_t v2 = std::string("abc");
 
   if (is_numeric(v))
       std::cout << *is_numeric(v) << std::endl;
 
   if (is_string(v2))
       std::cout << *is_string(v2) << std::endl;
 
   return 0;
}
 

С boost::variant всё будет аналогично:
Код
C++ (Qt)
#include <iostream>
#include <string>
#include <boost/optional.hpp>
#include <boost/variant.hpp>
 
typedef boost::variant<float, double, int, std::string> variant_t;
 
struct is_numeric : public boost::static_visitor<boost::optional<double>>
{
   result_type operator()(float v) const { return v; }
   result_type operator()(double v) const { return v; }
   result_type operator()(int v) const { return v; }
 
   template <class R>
   result_type operator()(R) const { return result_type(); }
};
 
 
struct is_string : public boost::static_visitor<boost::optional<std::string>>
{
   result_type operator()(const std::string & v) const { return v; }
 
   template <class R>
   result_type operator()(R) const { return result_type(); }
};
 
int main()
{
   variant_t v = 123;
 
   if (boost::apply_visitor(is_numeric(), v))
       std::cout << *boost::apply_visitor(is_numeric(), v) << std::endl;
 
   if (boost::apply_visitor(is_string(), v))
       std::cout << *boost::apply_visitor(is_string(), v) << std::endl;
 
   return 0;
}
 


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 18, 2015, 10:23
Как можно сортировать совместно числа и строки? Что больше 123 или "abc"?
Сообщите эти правила и я легко изменю функцию преобразования строки под ваши правила. Одну функцию исключительно для строки.
123 (число) должно быть меньше "abc". Здесь мы не ставим задачу сравнивать строки (посимвольно), пусть они сортируются "как получится", с этим никто не спорит. Но числа-то мы сравнивать хотим. Так сделайте чтобы сначала шли числа (что умеем/хотим сортировать), а потом уж все остальное (что сортировке не подлежит).

А это не возможно исправить без допущений, а с допущением делается легко и не принужденно и не убивает все ресурсы процессора на перебор типов.
Что-то не наблюдаю легкости. Напр задача чуть-чуть изменилась, теперь контейнер может содержать любые типы, но нас по прежнему интересуют только int, double и (валидный) string. И что-то я не соображу (по крайней мере сходу) как же это сделать с вумным обсервером  ???


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 18, 2015, 10:28
Значит, все строки, которые не представляют числа, должны конвертироваться в максимальное число, например, std::numeric_limits<double>::max()
Тогда, после сортировки, они все будут болтаться в хвосте коллекции.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 18, 2015, 11:04
Значит, все строки, которые не представляют числа, должны конвертироваться в максимальное число, например, std::numeric_limits<double>::max()
Тогда, после сортировки, они все будут болтаться в хвосте коллекции.

Но чтоб товарищу igors'у не было обидно, что он так и не увидел лёгкости, покажу как это можно сделать по-другому ("его методом" в контексте визитёра)..  

Код
C++ (Qt)
variant_visitor<boost::optional<double> (variant_t)> is_numeric;
   is_numeric.reg<double>([](variant_t v) { return v.get<double>(); });
   is_numeric.reg<int>([](variant_t v) { return v.get<int>(); });
   is_numeric.reg<float>([](variant_t v) { return v.get<float>(); });
 
   is_numeric.reg<std::string>([](variant_t v)->boost::optional<double>
   {
       try {
           return std::stod(v.get<std::string>());
       } catch (...) {
           return boost::optional<double>();
       }
   } );
 
 
   std::list<variant_t> list;
   list.push_back(1);
   list.push_back(123.456);
   list.push_back(std::string("abc"));
   list.push_back(std::string("6483.238578"));
 
   list.sort([&](variant_t v1, variant_t v2)->bool
   {
       auto x = is_numeric(v1);
       auto y = is_numeric(v2);
       return (x && y) ? (*x < *y) : (x && !y);
   });
 
 

... Может небольшую статью об этом патерне написать?)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 18, 2015, 13:58
Вот пример попроще - но с той же проблемой
Код
C++ (Qt)
#include <iostream>
#include <string>
#include <vector>
 
struct MyStruct {
MyStruct( int val = 0 ) : mUseText(false), mVal(val) {}
MyStruct( const char * str ) : mUseText(true), mStr(str) {}
 
bool operator < ( const MyStruct & sec ) const
{
if (mUseText || sec.mUseText) return false; // wrong
return mVal < sec.mVal;
}
 
// data
bool mUseText;
union {
int mVal;
const char * mStr;
};
};
 
int main( void )
{
std::vector <MyStruct> vec;
vec.push_back(MyStruct("str1"));
vec.push_back(MyStruct(5));
vec.push_back(MyStruct(2));
vec.push_back(MyStruct("str2"));
vec.push_back(MyStruct(1));
vec.push_back(MyStruct("str3"));
 
std::sort(vec.begin(), vec.end());
 
for (size_t i = 0; i < vec.size(); ++i)
if (vec[i].mUseText)
std::cout << vec[i].mStr << std::endl;
else
std::cout << vec[i].mVal << std::endl;
 
return 0;
}
 
Вывод
Цитировать
str1
2
5
str2
1
str3
Как видим, дело не только в том что "валидные/невалидные" эл-ты перемешаны, но и валидные отсортированы неверно.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 18, 2015, 14:07
Как видим, дело не только в том что "валидные/невалидные" эл-ты перемешаны, но и валидные отсортированы неверно.
Вот так исправьте:
Код
C++ (Qt)
struct MyStruct {
MyStruct( int val = 0 ) : mUseText(false), mVal(val) {}
MyStruct( const char * str ) : mUseText(true), mStr(str) {}
 
bool operator < ( const MyStruct & sec ) const
{
return toInt() < sec.toInt();
}
 
int toInt() const
{
return  mUseText? std::numeric_limits<int>::max() : mVal;
}
 
// data
bool mUseText;
union {
int mVal;
const char * mStr;
};
};
 

А с визитером будет еще проще.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 18, 2015, 15:24
... Может небольшую статью об этом патерне написать?)
С удовольствием почитаю - уж лучше Вы будете писать чем некоторые  :)

Вот так исправьте:
Вот в том-то и дело что это прямая ошибка которую надо исправлять.

2m_ax Ну хорошо , вот у меня есть Ваш код и нужно поддерживать еще тип, напр short. Я должен
Цитировать
template <class T>
struct numeric_visitor : public boost::static_visitor<T>
{
    T operator()(int val) const { return val; }
    T operator()(short val) const { return val; }  // добавить здесь

Цитировать
variant_visitor<boost::optional<double> (variant_t)> is_numeric;
    is_numeric.reg<int>([](variant_t v) { return v.get<int>(); });
    is_numeric.reg<short>([](variant_t v) { return v.get<short>(); });  // добавить здесь
И может где-то еще. Поясните, чем это отличается от редактирования "простыни" if-else-switch? Все равно "перебор", т.е. все типы должны быть явно указаны и все операции извлечения значения должны быть явно выписаны. "Зато" остатки моска выносятся бустовсими классами. А где же "выйгрыш"? :)


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 18, 2015, 15:54
Вот в том-то и дело что это прямая ошибка которую надо исправлять.
Вот я ее и исправил, в моем варианте все правильно сравнивается и сортируется, точнее согласно, выведенному нами выше, допущению: числа в правильном порядке впереди, строки в конце.


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 19, 2015, 14:32
Цитировать
Поясните, чем это отличается от редактирования "простыни" if-else-switch? Все равно "перебор", т.е. все типы должны быть явно указаны и все операции извлечения значения должны быть явно выписаны.
Нет, в том то и дело что для boost::variant/ boost::static_visitor это не обязательно..
Если я хочу извлечь число то достаточно написать пару строк:
Код
C++ (Qt)
typedef boost::variant<float, double, int, long, short, std::string> variant_t;
 
struct numeric : public boost::static_visitor<boost::optional<double>>
{
   template <class T>
   result_type operator()(T v) const
   {
       return std::is_arithmetic<T>::value ? v : result_type();
   }
 
   result_type operator()(const std::string & s) const
   {
       try {
           return std::stod(s);
       } catch (...) {
           return result_type();
       }
   }
};
 

Всё!
Вы же будете писать аналогичную функцию numeric, (которую мы уже видели) где будет вся это простыня с проверками на ВСЕ типы + ещё попытка преобразовать строку в число..



  


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 20, 2015, 11:43
Нет, в том то и дело что для boost::variant/ boost::static_visitor это не обязательно..
Если я хочу извлечь число то достаточно написать пару строк:
Код
C++ (Qt)
typedef boost::variant<float, double, int, long, short, std::string> variant_t;
 
struct numeric : public boost::static_visitor<boost::optional<double>>
{
   template <class T>
   result_type operator()(T v) const
   {
       return std::is_arithmetic<T>::value ? v : result_type();
   }
...
};
 

Всё!
Ну так и я могу, напр
Код
C++ (Qt)
QVariant v(5);
if (v.canConvert<double>())
double d = v.toDouble();
 
И как-то выглядит приятнее :) Но за этим та же самая "простыня", уже кем-то написанная.

Интересен такой момент: вот я, допустим, хочу создать MyClass "по образцу" и определил набор типов
Код
C++ (Qt)
typedef MyClass<float, double, int, long, short, std::string> ClassNum;
 
Что теперь - я могу извлекать/получать значения "непосредственно", напр
Код
C++ (Qt)
void Test( const ClassNum & src )
{
 double d = src;
 short s = src;      // неясно, а если src не влезет в short?
 std:::string s = src;
//  long long l = src; // а этого типа нет для ClassNum
}  
 
Или так нельзя, нужно только через визитор?
Спасибо


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 20, 2015, 12:54
Ну так и я могу, напр
Это не равнозначный код.

Что теперь - я могу извлекать/получать значения "непосредственно", напр
Код
C++ (Qt)
void Test( const ClassNum & src )
{
 double d = src;
 short s = src;      // неясно, а если src не влезет в short?
 std:::string s = src;
//  long long l = src; // а этого типа нет для ClassNum
}  
 

Можно сделать функцию, например, get, которая и будет конвертировать ClassNum во что скажете:
Код
C++ (Qt)
void Test( const ClassNum & src )
{
 double d = get<double>( src );
 short s = get<short>( src );      // Если не будет влазить в short - обрежется, а можно и исключение бросать об этом
 std::string str = get<std::string>( src );
 long long l = get<long long>( src ); // И не важно, что этого типа нет в варианте
 
 // или второй вариант get
 double d;
 get( d, src );
 short s;
 get( s, src );
 long long l;
 get( l, src );
}
 


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 20, 2015, 15:36
Можно сделать функцию, например, get, которая и будет конвертировать ClassNum во что скажете:
А какая техника изготовления таких ф-ций? Я полагаю что опять-таки сохранить тип в ClassNum явно и при извлечении "перебор". Или как-то все таки можно накрутить через enable_if и.т.п. ?


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Old от Февраль 20, 2015, 15:38
А какая техника изготовления таких ф-ций? Я полагаю что опять-таки сохранить тип в ClassNum явно и при извлечении "перебор". Или как-то все таки можно накрутить через enable_if и.т.п. ?

Код
C++ (Qt)
typedef boost::variant<short, int, long, float, double, std::string> var_t;
 
template<class T>
struct numeric : public boost::static_visitor<T>
{
template<class V>
T operator()( V val ) const
{
return std::is_arithmetic<V>::value ? val : std::numeric_limits<T>::max();
}
 
T operator()( const std::string &val ) const
{
try { return boost::lexical_cast<T>( val ); } catch(...) {}
return std::numeric_limits<T>::max();
}
};
 
struct literal : public boost::static_visitor<std::string>
{
template<class V>
std::string operator()( V val ) const
{
return boost::lexical_cast<std::string>( val );
}
};
 
template<class T>
T get( var_t v )
{
static_assert( std::is_arithmetic<T>::value, "Shit type T" );
return boost::apply_visitor( numeric<T>(), v );
}
 
template<>
std::string get<std::string>( var_t v )
{
return boost::apply_visitor( literal(), v );
}
 
template<class T>
void get( T &res, var_t v )
{
static_assert( std::is_arithmetic<T>::value, "Shit type T" );
res = boost::apply_visitor( numeric<T>(), v );
}
 
int main()
{
var_t v1 = 100000;
var_t v2 = 200000L;
var_t v3 = "300000";
var_t v4 = "test string";
 
ushort r1 = get<ushort>( v1 );
long r2 = get<long>( v2 );
double r3 = get<double>( v2 );
long long r4 = get<long long>( v1 );
float r5 = get<float>( v3 );
short r6 = get<short>( v3 );
std::string r7 = get<std::string>( v4 );
 
cout << "r1 (short) = " << r1 << endl
<< "r2 (long) = " << r2 << endl
<< "r3 (double) = " << r3 << endl
<< "r4 (long long) = " << r4 << endl
<< "r5 (float) = " << r5 << endl
<< "r6 (short) = " << r6 << endl
<< "r7 (string) = " << r7 << endl;
 
return 0;
}
 

Цитировать
r1 (short) = 34464
r2 (long) = 200000
r3 (double) = 200000
r4 (long long) = 100000
r5 (float) = 300000
r6 (short) = 32767
r7 (string) = test string


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: m_ax от Февраль 22, 2015, 18:10
navrovsky, в вашей реализации Variant, в методе tryGetValue нужно вначале сделать detach, иначе через этот метод можно изменять значения других объектов Variant
т.е.:
Код
C++ (Qt)
   Variant v1 = 10;
   Variant v2 = v1;  // у v2 и v1 теперь общие  данные
 
   int *a;
 
   v1.tryGetValue(a);
 
   std::cout << *a << std::endl;
 
   (*a) = 123;  
 
   std::cout << v2.value<int>() << std::endl; // v2 теперь тоже вернёт 123
 

Можно исправить так, например:
Код
C++ (Qt)
template <typename T>
   bool tryGetValue(T*& val)
   {
       if (!isType<T>())
           return false;
 
       if (!holder_.unique())
           holder_ = std::make_shared<Holder<T>>(typeid(T).name(), std::static_pointer_cast<Holder<T>>(holder_)->value);
 
       val = &(std::static_pointer_cast<Holder<T>>(holder_)->value);
       return true;
   }
 


Название: Re: (С++11) Variant - простой аналог boost::any
Отправлено: Igors от Февраль 23, 2015, 11:29
Код
C++ (Qt)
typedef boost::variant<short, int, long, float, double, std::string> var_t;
 
template<class T>
struct numeric : public boost::static_visitor<T>
{
template<class V>
T operator()( V val ) const
{
 
Да, здесь T - именно тот тип которым инициализирован вариант, это ценная возможность. Постарался разобраться как же он это делает, но увы, заблудился в дебрях макрух  :)