C ++ 17结构化绑定,还包含现有变量

时间:2017-03-04 00:05:01

标签: c++ refactoring c++17 structured-bindings

This SO answer列出了C ++ 17分解声明(以前称为“结构化绑定”)的一些缺点。例如,您不能为新变量提供显式类型,依此类推。但是我遇到的一个很大的缺点就是没有提到,所以我想知道是否有一个我不会想到的已知解决方法。

考虑this JSON-parsing code(可能包含其他错误;请出于此问题的目的忽略它们):

using Value = std::any;
using String = std::string;
using Object = std::map<String, Value>;

std::pair<String, const char *> load_string(const char *p, const char *end);
std::pair<Value, const char *> load_value(const char *p, const char *end);
const char *skip_spaces(const char *p, const char *end);

std::pair<Object, const char *> load_object(const char *p, const char *end)
{
    p = skip_spaces(p, end);
    if (p == end || *p++ != '{') throw ParseError("Expected {");
    p = skip_spaces(p, end);
    Object result;
    if (p == end && *p == '}') {
        // the object has no key-value pairs at all
    } else {
        while (true) {
            auto [key, p] = load_string(p, end);
            p = skip_spaces(p, end);
            if (p == end || *p++ != ':') throw ParseError("Expected :");
            auto [value, p] = load_value(p, end);
            result.insert_or_assign(std::move(key), std::move(value));
            p = skip_spaces(p, end);
            if (p == end) throw ParseError("Expected , or }");
            if (*p == '}') break;
            if (*p++ != ',') throw ParseError("Expected , or }");
        }
    }
    return {result, p+1};
}

除了从auto [key, p] =auto [value, p] =开始的行无效之外,这会很有效!变量p已经声明。我正在尝试为p分配一个新的,但我不想创建一个全新的本地变量

我不想使用std::tie(key, p) =,因为这需要我在分配前给key声明。这是对std::tie的熟悉的旧反对意见。我可以宣誓就是将结构化绑定引入语言的原因!

那么有没有任何解决方法 - 任何编写组合构造的简洁方法 - key - 就地 - 并且也分配给 - p表达我的意图< / em>的

我以前从未错过这个功能,这很奇怪,但是一旦你给我结构化绑定,我尝试的第一件事就行不通了。 :(

2 个答案:

答案 0 :(得分:0)

这是一个非常愚蠢的想法,我不会认真建议,除非最终没有理智的解决方法......但请考虑以下代码。

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);

它仍有一个限制,即“绑定”左值被限制为 last ,而“声明”变量被约束为 first ,但我不认为有很多方法来解决这个问题。如果你需要它,tuple_shuffle<Is...>之类的东西可以处理它。

答案 1 :(得分:0)

在类型更复杂的情况下,可移动临时新对象的简单变通方法可能是您想要的方向上最简单的可取步骤(尽管我认为在您的特殊情况下,遵循传统的{{ 1}}):

tie

对不起,我最终无法自己编译它,尽管我认为它是我的IDE(目前仅一半支持C ++ 17的CLion)的问题,尽管我希望它可以正常运行。 / p>