【问题标题】:Tuples of unknown size/parameter types未知大小/参数类型的元组
【发布时间】:2010-03-10 12:02:10
【问题描述】:

我需要创建一个映射,从整数到元组集合,单个集合中的元组具有相同的大小。问题在于元组的大小及其参数类型可以在运行时确定,而不是在编译时确定。我在想象这样的事情:

std::map<int, std::set<boost::tuple> >

但不完全确定如何准确地做到这一点,主要是使用指针。

这样做的目的是创建临时关系(表),每个都有唯一的标识符(键),也许你有另一种方法。

【问题讨论】:

  • 请澄清:一个集合只存储相同大小的元组,但不同的集合可以有不同的元组大小?
  • 是的,一个集合只存储相同大小的元组,但不同的集合可以有不同的元组大小。
  • 你想在编译时对元组中所有大小相同的元素施加限制吗?此外,元组可以是任何类型,其中一个元组具有相同类型的数据?
  • 我只插入整数。
  • 如果只插入一种类型的值,为什么要使用元组?除非您有一些未指定的限制,否则为什么不使用 std::vector (这很可能最终会比您可能设计的能够使用 boost::tuple 的任何解决方法更便宜和更强大)?​​

标签: c++ boost-tuples


【解决方案1】:

boost::tuple 的目的是混合任意类型。如果,如你所说,

我只插入整数

那么你应该使用map&lt; int, set&lt; vector&lt; int &gt; &gt; &gt;。 (如果我是你,我会扔一些typedefs。)

不过,为了回答最初的问题,boost::tuple 不允许在运行时使用任意类型。 boost::any 确实如此。但是,any 不支持比较,因此如果您想在 set 中使用它,还需要做一些工作。

typedef vector< boost::any > tuple;
struct compare_tuple { bool operator()( tuple const &l, tuple const &r ) const {
    assert ( l.size() == r.size() );

    for ( tuple::iterator lit = l.begin(), rit = r.begin();
          lit != l.end(); ++ lit, ++ rit ) {
        assert ( lit->type() == rit->type() );

        if ( lit->type() == typeid( foo ) ) { // find the type and perform "<"
            return boost::any_cast<foo>(*lit) < boost::any_cast<foo>(*rit);
        } else if ( lit->type() == typeid( bar ) ) {
            return boost::any_cast<bar>(*lit) < boost::any_cast<bar>(*rit);
        } /* etc; you will need to enumerate all the types you can insert */
    }
} };

typedef std::map< int, std::set< tuple, compare_tuple > > main_map;

【讨论】:

    【解决方案2】:

    作为一个现代的旁注(因为以前的答案是大约 2010 年),今天的可变参数模板将对此很有用:

    template<typename... Args> //Accept any number of arguments and types
    auto MyFunction(std::tuple<Args...> &T)->void
    {
       //Do stuff...
    }
    

    【讨论】:

      【解决方案3】:

      如果您有一些共同的基类,您只能将这些不同的集合存储在同一个集合中。您可以编写一个抽象接口,然后为每种表/元组实现它。问题是,通常这样的接口往往非常混乱,如果你有许多类型的表/元组,你可能会发生类爆炸。 Boost.Any 对于这样的接口可能很有用(因为您必须动态处理不同的数据类型)。

      【讨论】:

        【解决方案4】:

        如果参数类型有共同点,将其捕获到抽象基类中,并使元组包含指向该基类的指针:

        class MyParamBase {
        public:
            virtual int getFoo() = 0;
            virtual void setFoo(int) = 0;
        };
        
        std::map<int, std::set<MyParamBase*> > container;
        

        (为简洁起见省略了 boost::tuple。不知道为什么需要一组元组。)

        然后您可以从 MyParamBase 派生具体参数类型并创建它们并将它们插入到地图中:

        class SomeParam: MyParamBase {
        public:
            virtual int getFoo() { ... }
            virtual void setFoo(int a) { ... }
        };
        
        std::set<MyParamBase*> some_set;
        some_set.insert(new SomeParam());
        container[123] = some_set;
        

        如果参数类型没有共同点 - 不要将它们放在同一个映射中。他们很可能不属于一起。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-07-30
          • 2016-03-03
          • 2013-11-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多