如何在不诉诸std :: function的情况下存储函数对象?

时间:2016-01-24 16:39:11

标签: c++ templates c++11 lambda

我正在尝试创建一个容纳对象及其位置的通用容器:

class Vector;

template <typename T>
class Container 
{
public:
    void insert(const T& t)
    {
        insertAtPosition(t.getPosition() ,t);
    }
private:
    void insertAtPosition(const Vector& v, const T& t);
    ...
} ;

但是,如果用户的对象位置获取器未被调用getPosition

,该怎么办?

如何根据容器内部获取商品位置的方式使此容器具有通用性?

到目前为止,我已经考虑了3种方法,其中没有一种是理想的:

  1. std::function<const Vector& (const T& t)>成员添加到Container
  2. 这是一个干净的C ++解决方案,但是这个函数会被非常频繁地调用,并且可能会导致显着的性能下降。

    1. 将一个仿函数对象添加到容器中:

      class Vector;
      
      template <typename T, typename TGetPosition>
      class Container 
      {
      public:
           Container(TGetPosition getPosition): getPosition_(getPosition){}
      
           void insert(const T& t)
           {
               insertAtPosition(getPosition_(t) ,t);
           }
      private:
           void insertAtPosition(const Vector& v, const T& t);
           TGetPosition getPosition_;
      } ;
      
    2. 我可以使用object generator idiom来使用lambdas:

      template <typename T, typename TGetPosition>
      Container<T, TGetPosition> makeContainer(TGetPosition getter)
      {
          return Container<T, TGetPosition>(getter);
      }
      
      ...
      
      auto container = makeSimpleContainer<Widget>([](const Widget& w)
          {
              return w.tellMeWhereYourPositionMightBe();
          });
      

      没有性能开销,但在某些情况下无法获得此类容器的类型。例如,你不能创建一个将这样的容器作为参数的类,因为decltype不起作用,因为lambdas不能在未评估的上下文中使用。

      1. 使用#define GETTER getPosition,用户只需将getPosition更改为他喜欢的内容即可。这种方法有很多问题,我甚至不知道从哪里开始。
      2. 拜托,还有其他方法吗?我错过了什么。欢迎任何指导!

        编辑:

        关于解决方案2:我不知道如何获得使用lambda函数创建的容器类型。一种方法是:

        using TContainer = decltype(makeSimpleContainer<Widget>([](const Widget& w)
            {
                return w.tellMeWhereYourPositionMightBe();
            });)
        

        但是这不起作用,因为lambdas不能用于未评估的上下文中。

2 个答案:

答案 0 :(得分:1)

合理可用的选项是期望上下文具有position_for()

template <class T> struct Container {
    size_t insert(T const& x) {
        insertAtPosition(position_for(x), x);
    }
};

Vector const& position_for(const Widget& w) {
    return ...;
}

Container<Widget> c;
c.insert(Widget());

...但是容器从业务对象生成密钥的设计通常不能很好地进行,因为查找虚拟对象需要进行操作,这可能很昂贵。

答案 1 :(得分:1)

即使您需要创建一个容纳容器的类,您的第二个解决方案似乎仍然有效:

template <typename Container>
struct SomeClass {
    SomeClass(const Container &container) : container(container) { }
    Container container;
};


int main()
{
    auto container = makeSimpleContainer<Widget>([](const Widget& w)
        {
            return w.tellMeWhereYourPositionMightBe();
        });
    SomeClass<decltype(container)> test(container);
}