如何解决嵌套名称说明符中使用的不完整类型`std :: variant <...>`
我将以下代码写入了名为main.cpp
的文件中。
它涉及标准类型为std::variant
的奇怪重复模板模式(CRTP)。
#include <string>
#include <variant>
#include <vector>
template<typename T>
struct either {
std::vector<T> arg;
};
template<typename T>
struct maybe_either: std::variant<T,either<maybe_either<T>>> {
template<typename U>
maybe_either(U&& v):
std::variant<T,either<maybe_either<T>>>(std::forward<U>(v)) {
}
};
struct var {
std::string name;
};
int main(int,char**) {
auto expression = maybe_either<var>(either<maybe_either<var>>{});
std::visit([&](auto&& v) {
using T = std::decay_t<decltype (v)>;
if constexpr (std::is_same_v<T,var>) {
// ...
} else if constexpr (std::is_same_v<T,either<maybe_either<var>>>) {
// ...
}
},expression);
return 0;
}
使用以下命令行进行编译时,出现以下错误消息:
$ g++ -c -std=c++17 main.cpp
In file included from main.cpp:2:0:
/usr/include/c++/7/variant: In instantiation of ‘constexpr const size_t std::variant_size_v<maybe_either<var> >’:
/usr/include/c++/7/variant:702:10: required from ‘struct std::__detail::__variant::__gen_vtable<void,main(int,char**)::<lambda(auto:1&&)>&&,maybe_either<var>&>’
/usr/include/c++/7/variant:1255:23: required from ‘constexpr decltype(auto) std::visit(_Visitor&&,_Variants&& ...) [with _Visitor = main(int,char**)::<lambda(auto:1&&)>; _Variants = {maybe_either<var>&}]’
main.cpp:32:18: required from here
/usr/include/c++/7/variant:97:29: error: incomplete type ‘std::variant_size<maybe_either<var> >’ used in nested name specifier
inline constexpr size_t variant_size_v = variant_size<_Variant>::value;
^~~~~~~~~~~~~~
/usr/include/c++/7/variant: In instantiation of ‘constexpr const auto std::__detail::__variant::__gen_vtable<void,maybe_either<var>&>::_S_vtable’:
/usr/include/c++/7/variant:711:29: required from ‘struct std::__detail::__variant::__gen_vtable<void,char**)::<lambda(auto:1&&)>; _Variants = {maybe_either<var>&}]’
main.cpp:32:18: required from here
/usr/include/c++/7/variant:711:49: error: ‘_S_apply’ was not declared in this scope
static constexpr auto _S_vtable = _S_apply();
~~~~~~~~^~
我从maybe_either
派生的类std::variant<...>
可以在其他上下文中正常使用,但是当我在其上调用std::visit(...)
时,它将无法编译。怎么了?
解决方法
maybe_either<T>
不是std::variant
的专业化-它继承自一个。并且std::visit
当前未指定。尚不清楚允许访问哪种“变体”。
libstdc ++在该库问题中实现了原始建议的方向,这是std::variant
的 only 专长(不是)。另一方面,libc ++允许访问从std::variant
继承的类型,因此访问accepts your example。
目的是原样的示例最终将变得格式正确。但是在那之前,您必须确保所进行的访问直接在std::variant
上。您可以通过添加自己的成员或非成员visit
来执行此操作,这样,调用方就不必自己这样做。
例如,这个:
template<typename T>
struct maybe_either: std::variant<T,either<maybe_either<T>>> {
using base = typename maybe_either::variant;
template<typename U>
maybe_either(U&& v):
std::variant<T,either<maybe_either<T>>>(std::forward<U>(v)) {
}
template <typename F>
decltype(auto) visit(F&& f) & {
return std::visit(std::forward<F>(f),static_cast<base&>(*this));
}
};
允许使用此to work:
int main(int,char**) {
auto expression = maybe_either<var>(either<maybe_either<var>>{});
expression.visit([&](auto&& v) {
using T = std::decay_t<decltype (v)>;
if constexpr (std::is_same_v<T,var>) {
// ...
} else if constexpr (std::is_same_v<T,either<maybe_either<var>>>) {
// ...
}
});
return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。