1

Consider the following class foo:

class foo {
private:
    int x = 0;
    int y = 0;

public:
    template <std::size_t I>
    int const& get() const
    {
        if constexpr (I == 0) {
            return x;
        }
        else return y;
    }
};

I would like to implement structured bindings for foo, so I added the following:

namespace std {
    template <>
    struct tuple_size<foo> : std::integral_constant<std::size_t, 2u> {};

    template <std::size_t I>
    struct tuple_element<I, foo> {
        using type = int;
    };
}

Now, if the user is to perform structure bindings, he/she has to explicitly add a const qualifier:

int main() {
    foo f;
    auto [a, b] = f;            // Won't compile
    auto& [x, y] = f;           // Won't compile
    const auto [c_a, c_b] = f;  // Compiles
    const auto& [c_x, c_y] = f; // Compiles
    return 0;
}

(Because we cannot bind int& to a int const&)

Or, alternatively, I can make tuple_element typedef a const int. Now all four statements compiles:

namespace std {
    template <>
    struct tuple_size<foo> : std::integral_constant<std::size_t, 2u> {};

    template <std::size_t I>
    struct tuple_element<I, foo> {
        using type = const int;         // <=== const added here
    };
}

int main() {
    foo f;
    auto [a, b] = f;            // Compiles
    auto& [x, y] = f;           // Compiles
    const auto [c_a, c_b] = f;  // Compiles
    const auto& [c_x, c_y] = f; // Compiles
    return 0;
}

Now note that even if no const qualifier is present in their declarations, a, b, x, and y are all int const. This might be confusing to the user.

So my question is: which one of the above is considered a better practice?

4

1 回答 1

2

所以我的问题是:以上哪一项被认为是更好的做法?

更喜欢第二种方法来尝试模仿内置和标准发生的情况:

class foo {
public:
    const int x = 0;
    const int y = 0;
};

int main() {
    foo f;
    auto [a, b] = f;            // Compiles
    auto& [x, y] = f;           // Compiles
    const auto [c_a, c_b] = f;  // Compiles
    const auto& [c_x, c_y] = f; // Compiles
}

并且来自binding_a_tuple-like_type

std::tuple<float&,char&&,int> tpl(x,std::move(y),z);
const auto& [a,b,c] = tpl;
// a names a structured binding that refers to x; decltype(a) is float&
// b names a structured binding that refers to y; decltype(b) is char&&
// c names a structured binding that refers to the 3rd element of tpl; decltype(c) is const int

于 2019-12-23T09:49:10.507 回答