fender0107401 发表于 2014-11-18 12:11

Boost里面的any和variant很好玩。


不过似乎没啥用途。

windoze 发表于 2014-11-18 13:00

回复 1# fender0107401

any可以拿来做异构容器,variant其实就是tagged union,都挺有用的。

hellioncu 发表于 2014-11-18 13:09

只用过COM中的variant

linux_c_py_php 发表于 2014-11-18 13:21

不用也不会受影响,用了可以简化一些东西。

windoze 发表于 2014-11-19 10:27

回复 4# linux_c_py_php

如果你有这样的代码
struct var {
    int tag;
    union {
      int int_value;
      double double_value;
    };
}

switch(x.tag) {
case INTEGER:
    // do something with x.int_value
    break;
case DOUBLE:
    // do something with x.double_value
    break;
default:
    // unknown tag
};
可以用boost.variant简化成这样:
typedef boost::variant<int, double> var;
struct something_visitor : public boost::static_visitor<> {
    void operator()(int int_value) { /* do something with int_value */ }
    void operator()(double double_value) { /* do something with double_value */ }
    template<typename T> void operator()(T t) { /* unknown type */ }
};
boost::apply_visitor(something_visitor(), x);
代码好看一些

lost_templar 发表于 2014-11-20 19:43

windoze 发表于 2014-11-19 10:27 static/image/common/back.gif
回复 4# linux_c_py_php

如果你有这样的代码可以用boost.variant简化成这样:代码好看一些

Isn't this a simple multi-overloader?
template< typename Arg, typename ... Args >
struct overloader : Arg, overloader<Args...>
{
    overloader( Arg arg_, Args ... args_ ) : Arg(arg_), overloader<Args...>( args_... ) {}
};
template< typename Arg >
struct overloader<Arg> : Arg
{
    overloader( Arg arg_ ) : Arg(arg_){}
};
template< typename ... Args >
auto make_overloader( Args ... args_ )
{
   return overloader<Args...>{ args_... };
}

auto visitor = make_overloader( []( int i ) {...}, []( double d ){...} );
int ix;
double dx;
visitor( ix );
visitor( dx );

windoze 发表于 2014-11-20 21:20

回复 6# lost_templar

你这样只解决了overload,没解决union的问题。

lost_templar 发表于 2014-11-20 22:02

windoze 发表于 2014-11-20 21:20 static/image/common/back.gif
回复 6# lost_templar

你这样只解决了overload,没解决union的问题。

很少接触 union, 不知你举的例子中是什么样子的场景,非用 union 不可?

对 union 的认识还停留在节省内存之类的初级阶段,而我用来计算的机器有 128 G 内存,根本想不起用 union.

windoze 发表于 2014-11-20 22:12

回复 8# lost_templar

我是说tagged union,也就是Algebraic data type,能存一组不同类型的数据,通过一个tag标记到底保存了什么类型。
这种东西其实经常能用到,比如说一个JSON value,就有可能是一个数字、字符串、数组或者一个map,你要实现这么个东西就需要一个类似的结构。

lost_templar 发表于 2014-11-20 22:36

windoze 发表于 2014-11-20 22:12 static/image/common/back.gif
回复 8# lost_templar

我是说tagged union,也就是Algebraic data type,能存一组不同类型的数据,通过一个tag标记到底保存了什么类型。
这种东西其实经常能用到,比如说一个JSON value,就有可能是一个数字、字符串、数组或者一个map,你要实现这么个东西就需要一个类似的结构。

如果让我存储一组不同类型的数据,我可能直接用一个 lambda 函数或 tuple 做容器,这样来做
template<typename ... Args >
auto container( Args ... args )
{
    return [=]( auto function ){ return function( args... ); };
}
加上前文的 overloadertemplate< typename Arg, typename ... Args >
struct overloader : Arg, overloader<Args...>
{
    overloader( Arg arg_, Args ... args_ ) : Arg(arg_), overloader<Args...>( args_... ) {}
};
template< typename Arg >
struct overloader<Arg> : Arg
{
    overloader( Arg arg_ ) : Arg(arg_){}
};
template< typename ... Args >
auto make_overloader( Args ... args_ )
{
   return overloader<Args...>{ args_... };
}再加上一个 function mapper 来处理容器里边的数据
template< typename F >
auto function_mapper( F f )
{
    return [=]( auto ... args ){ return container( f(args)... ); };
}
这样一来,就可以直接存储不同类型的数据到一个 lambda 中去
auto my_data = container( 1, 1.0, "data", true, 4.3 );
然后针对存储的类型生成处理函数
auto process = make_overloader( []( int i ){...}, []( double d){...}, [](bool b){...}, [](string s){...} );
最后将这个函数应用到 lambda 容器上去
my_data( function_mapper( process ) );
页: [1] 2
查看完整版本: Boost里面的any和variant很好玩。