C++ C++;17还包括现有变量的结构化绑定
列出了C++17分解声明(以前称为“结构化绑定”的功能)的一些缺点。例如,不能为新变量提供显式类型,等等。但是我遇到的一个大缺点没有提到,所以我想知道是否有一个已知的解决方法,我只是没有想到 考虑(可能包含其他bug;出于本问题的目的,请忽略它们):C++ C++;17还包括现有变量的结构化绑定,c++,refactoring,c++17,structured-bindings,C++,Refactoring,C++17,Structured Bindings,列出了C++17分解声明(以前称为“结构化绑定”的功能)的一些缺点。例如,不能为新变量提供显式类型,等等。但是我遇到的一个大缺点没有提到,所以我想知道是否有一个已知的解决方法,我只是没有想到 考虑(可能包含其他bug;出于本问题的目的,请忽略它们): 使用Value=std::any; 使用String=std::String; 使用Object=std::map; std::pair load_字符串(const char*p,const char*end); std::pair load_值
使用Value=std::any;
使用String=std::String;
使用Object=std::map;
std::pair load_字符串(const char*p,const char*end);
std::pair load_值(常量字符*p,常量字符*end);
常量字符*跳过空格(常量字符*p,常量字符*end);
std::pair load_对象(const char*p,const char*end)
{
p=跳过空格(p,结束);
如果(p==end | |*p++!='{')抛出语法错误(“预期的{”);
p=跳过空格(p,结束);
客观结果;
如果(p==end&&*p=='}'){
//对象根本没有键值对
}否则{
while(true){
自动[键,p]=加载字符串(p,结束);
p=跳过空格(p,结束);
如果(p==end | |*p++!=':')抛出ParseError(“预期:”);
自动[值,p]=加载值(p,结束);
结果。插入_或_赋值(std::move(键),std::move(值));
p=跳过空格(p,结束);
if(p==end)抛出ParseError(“预期的,或}”);
如果(*p='}')中断;
如果(*p++!=',')抛出语法错误(“预期的,或}”);
}
}
返回{result,p+1};
}
这将非常有效,除了以auto[key,p]=
和auto[value,p]=
开头的行无效之外!变量p
已声明。我试图给p
赋值,但我不想创建一个全新的局部变量
我不希望使用std::tie(key,p)=
,因为这要求我在分配任务之前声明key
。这是对std::tie
的常见反对意见。我可以发誓这就是结构化绑定被引入语言的原因
那么,是否有任何变通方法——任何一种写组合结构的简洁方法——键
——以及分配给-p
来表达我的意图
奇怪的是,我以前从未错过过这个功能,但一旦你给我结构化绑定,我尝试的第一件事就行不通了(
这是一个非常愚蠢的想法,除非最终没有健全的解决方案,否则我不会认真地建议……但是请考虑下面的代码。
template<size_t P, size_t... Is>
auto plus(std::index_sequence<Is...>)
{
return std::index_sequence<P+Is...>{};
}
template<typename RHS, size_t... Is>
auto tuple_select(RHS&& rhs, std::index_sequence<Is...>)
{
return std::forward_as_tuple(std::get<Is>(std::forward<RHS>(rhs))...);
}
template<typename... Ts>
struct AndTie {
std::tuple<Ts&...> v;
AndTie(Ts&... vs) : v(vs...) {}
template<typename RHS>
auto operator=(RHS&& rhs) && {
constexpr int N = std::tuple_size_v<RHS>;
constexpr int K = sizeof...(Ts);
v = tuple_select(std::forward<RHS>(rhs), plus<N-K>(std::make_index_sequence<K>{}));
return tuple_select(std::forward<RHS>(rhs), std::make_index_sequence<N-K>{});
}
};
它仍然有一个限制,即“绑定”左值被限制在最后出现,“声明”变量被限制为首先出现,但我认为没有太多的方法可以解决这个问题。如果需要的话,像
tuple\u shuffle
这样的东西可以处理这个问题。在类型更复杂的情况下,一个可移动的临时新对象的简单解决方法可能是朝着你想要的方向迈出的最简单的一步(尽管我认为在您的特殊情况下,坚持传统的领带可能更简单):
很抱歉,我最终无法自己编译它,虽然我可以看出这是我的IDE(CLion目前只支持C++17的一半)的一个问题,但我希望它能正常工作。如果分解声明auto[a1,a2,…,an]=s;
首先准确地提取n
元素,无论其编号是否为>n
@Orient:我碰巧同意;但即使是这样,它也不会直接解决我的问题,对吗?现在我想-不。需要一种相当于将数据成员“解包”到函数argumen列表中的能力。
template<size_t P, size_t... Is>
auto plus(std::index_sequence<Is...>)
{
return std::index_sequence<P+Is...>{};
}
template<typename RHS, size_t... Is>
auto tuple_select(RHS&& rhs, std::index_sequence<Is...>)
{
return std::forward_as_tuple(std::get<Is>(std::forward<RHS>(rhs))...);
}
template<typename... Ts>
struct AndTie {
std::tuple<Ts&...> v;
AndTie(Ts&... vs) : v(vs...) {}
template<typename RHS>
auto operator=(RHS&& rhs) && {
constexpr int N = std::tuple_size_v<RHS>;
constexpr int K = sizeof...(Ts);
v = tuple_select(std::forward<RHS>(rhs), plus<N-K>(std::make_index_sequence<K>{}));
return tuple_select(std::forward<RHS>(rhs), std::make_index_sequence<N-K>{});
}
};
auto [key] =AndTie(p)= load_string(p, end);
auto [value] =AndTie(p)= load_value(p, end);
... // (as in your code: p & end exist already, key & p_ not yet)
auto [key, p_] = load_string(p, end);
p = move(p_);
... // (continue using p)