假设我们想要使用动态 C++ 类型对 C 结构建模。 IE。我们有一组字段,每个字段都有一个名称和一个值。该值可以是简单的基本类型(为了示例,我们只说 int
)或其他结构,即另一组字段。
这很简单:
template <typename RecursiveVariant>
struct Field
{
std::string name;
RecursiveVariant value;
};
template <typename RecursiveVariant>
using StructFields = std::vector<Field<RecursiveVariant>>;
typedef typename boost::make_recursive_variant<
int
, StructFields<boost::recursive_variant_>
>::type FieldValue;
int main(int argc, char* argv[])
{
FieldValue fv = 2;
StructFields<FieldValue> sf;
Field<FieldValue> f{"name", 2};
sf.push_back(f);
fv = sf;
return 0;
}
它按预期工作。但是,如果我们尝试使用 multi_index_container
而不是 std::vector
,它将无法编译。如果我将 StructFields
的定义更改为:
template <typename RecursiveVariant>
using StructFields = multi_index_container<
Field<RecursiveVariant>
, indexed_by<
sequenced<>
, ordered_unique<
member<
Field<RecursiveVariant>
, std::string
, &Field<RecursiveVariant>::name
>
>
>
>;
编译器(来自 VS 15.6.3 的 MSVC)将发出
二进制“=”:未找到接受类型为“boost::multi_index::multi_index_container,boost::multi_index::multi_index_container, ...”的右手操作数的运算符
在线投诉 fv = sf
。它提示 variant& operator=(const variant& rhs)
和 variant& operator=(variant&& rhs)
之间的歧义。我不确定这些 operator=
是如何参与的。有解决这个问题的方法吗?
最佳答案
与@sehe 一样,我怀疑问题与 Boost.MPL 魔术(特别是所谓的占位符表达式的识别)有关,但不知道为什么会失败。
FWIW,替换 using StructFields
带有硬类型定义的位似乎可以解决问题:
template <typename RecursiveVariant>
struct StructFields: multi_index_container<
Field<RecursiveVariant>
, indexed_by<
sequenced<>
, ordered_unique<
member<
Field<RecursiveVariant>
, std::string
, &Field<RecursiveVariant>::name
>
>
>
>{};
或者,更好的是,只对索引执行硬类型技巧:
template <typename RecursiveVariant>
struct StructFieldsIndices:indexed_by<
sequenced<>
, ordered_unique<
member<
Field<RecursiveVariant>
, std::string
, &Field<RecursiveVariant>::name
>
>
>{};
template <typename RecursiveVariant>
using StructFields = multi_index_container<
Field<RecursiveVariant>
, StructFieldsIndices<RecursiveVariant>
>;
后记:好的,我想我知道发生了什么。如前所述,使用“更简单”的索引(例如 sequenced
)时不会出现问题。或 random_access
, 是在扔ordered_unique
的时候因为事情失败了。这三个是索引说明符声明如下:
template <typename TagList=tag<> >
struct sequenced;
template <typename TagList=tag<> >
struct random_access;
template<typename Arg1,typename Arg2=mpl::na,typename Arg3=mpl::na>
struct ordered_unique;
ordered_unique
的特殊性是它的mpl::na
默认值:在定义 StructFields<boost::recursive_variant_>
的上下文中,Boost.MPL“看到”那些mpl::na
通过 ordered_unique
层并且无法将整个类型识别为具有一个 arg 的占位符表达式。
后记:我现在真的觉得这是怎么回事:-)而且它与mpl::na
无关(实际上,sequenced
在其默认的 mpl::na
= tag<>
参数中隐藏了 tag<mp::na,...,mpl::na>
并且不会引发任何错误)。问题与 &Field<RecursiveVariant>::name
有关arg member
以及 Boost.MPL 无法替代 &Field<FieldValue>::name
对于 &Field<boost::recursive_variant_>::name
在处理占位符表达式时(我猜是因为这是一个非类型 模板参数)。因此,您可以将硬类型技巧限制为仅定义 member
如下:
template <typename RecursiveVariant>
struct FieldName: member<
Field<RecursiveVariant>
, std::string
, &Field<RecursiveVariant>::name
>{};
template <typename RecursiveVariant>
using StructFields = multi_index_container<
Field<RecursiveVariant>
, indexed_by<
sequenced<>
, ordered_unique<FieldName<RecursiveVariant>>
>
>;
关于c++ - 由于 operator= 不明确,multi_index_container 不适用于递归变体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49371896/