0

我正在尝试实现 Boost::variant 对象的 multi_index 容器。该变体由一个公共基础对象的两个派生类组成。我在每个派生类(“extractKey()”)中实现了一个虚函数,它返回一个 std::pair<char,char> 以提供合适的键值,而不管哪个派生对象占据了变体。

如何使用 apply_visitor()(可能在 lambda 表达式中?)调用“extractKey()”函数作为 CONST_MEM_FUN 键提取器以获得键值?为了实现这一点,我无法获得正确的语法。

我正在使用 Visual Studio 2019 和 C++17。

编辑:虽然我已经有了一个更加理智和传统的解决方案,它只是在派生对象中使用基对象指针和虚函数的容器(并且没有变体!)其他场景需要存储根本不同的对象(不是派生来自一个公共基础对象)在一个 multi_index 容器中。这就是我希望找到这里提出的问题的解决方案的真正原因。

4

1 回答 1

0

解决此问题的最佳方法是提供您自己的用户定义的密钥提取器。请注意,变体类型派生自一个公共基础这一事实在这里没有任何重要作用:在没有继承的情况下,只需应用一个常规访问者来处理变体中的所有类型(如果所有类型都符合获取密钥的相同语法)。

Live Coliru Demo

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/variant/variant.hpp>
#include <utility>

struct base
{
  virtual ~base()=default;
  virtual std::pair<char,char> extractKey()const=0;
};

struct derived1:base
{
  std::pair<char,char> extractKey()const override{return{1,0};};
};

struct derived2:base
{
  std::pair<char,char> extractKey()const override{return{0,1};};
};

using namespace boost::multi_index;

using variant=boost::variant<derived1,derived2>;

struct variant_key
{
  using result_type=std::pair<char,char>;
  
  auto operator()(const variant& x)const
  {
    return boost::apply_visitor(
      [](const base& b){return b.extractKey();},
      x
    );
  }
};

using container=multi_index_container<
  variant,
  indexed_by<
    ordered_non_unique<variant_key>
  >
>;

// testing

#include <iostream>

template<typename... Ts> struct overloaded:Ts...{using Ts::operator()...;};
template<typename... Ts> overloaded(Ts...)->overloaded<Ts...>;

int main()
{
  container c;
  for(int i=2;i--;){
    c.insert(variant(derived1()));
    c.insert(variant(derived2()));
  }
  
  for(const auto& x:c){
    boost::apply_visitor(
      overloaded{
        [](const derived1&){std::cout<<"derived1 ";},
        [](const derived2&){std::cout<<"derived2 ";}
      },
      x
    );
  }
}

输出

derived2 derived2 derived1 derived1 
于 2021-10-22T15:29:23.170 回答