是否可以为 Boost 变体的容器创建 Boost multi_index MEM_FUN 密钥提取器?
Is it possible to create Boost multi_index MEM_FUN key extractors for a container of Boost variant?
我正在尝试实现 multi_index 个包含 Boost::variant 个对象的容器。该变体由一个公共基础对象的两个派生 classes 组成。我在每个派生 class ("extractKey()") which returns a std::pair 中实现了一个虚函数来提供合适的键值,而不管哪个派生对象占用变体。
如何使用 apply_visitor()(可能在 lambda 表达式中?)调用“extractKey()”函数作为 CONST_MEM_FUN 键提取器以获得键值?为了完成此操作,我无法获得正确的语法。
我正在使用 Visual Studio 2019 和 C++17。
编辑:虽然我已经有了一个更加理智和传统的解决方案,它只是在派生对象中使用基本对象指针和虚函数的容器(没有变体!)在需要在 multi_index 容器中存储根本不同的对象(不是从公共基础对象派生)的情况下,会出现其他情况。这就是我希望找到这里提出的问题的解决方案的真正原因。
解决此问题的最佳方法是提供您自己的 user-defined key extractor。请注意,变体类型派生自公共基础这一事实在这里并没有发挥任何重要作用:在没有继承的情况下,只需应用一个常规访问者来处理变体中的所有类型(可能使用通用 lambda,如果所有类型都符合获取密钥的相同语法。
#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
我正在尝试实现 multi_index 个包含 Boost::variant 个对象的容器。该变体由一个公共基础对象的两个派生 classes 组成。我在每个派生 class ("extractKey()") which returns a std::pair
如何使用 apply_visitor()(可能在 lambda 表达式中?)调用“extractKey()”函数作为 CONST_MEM_FUN 键提取器以获得键值?为了完成此操作,我无法获得正确的语法。
我正在使用 Visual Studio 2019 和 C++17。
编辑:虽然我已经有了一个更加理智和传统的解决方案,它只是在派生对象中使用基本对象指针和虚函数的容器(没有变体!)在需要在 multi_index 容器中存储根本不同的对象(不是从公共基础对象派生)的情况下,会出现其他情况。这就是我希望找到这里提出的问题的解决方案的真正原因。
解决此问题的最佳方法是提供您自己的 user-defined key extractor。请注意,变体类型派生自公共基础这一事实在这里并没有发挥任何重要作用:在没有继承的情况下,只需应用一个常规访问者来处理变体中的所有类型(可能使用通用 lambda,如果所有类型都符合获取密钥的相同语法。
#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