On Wed, Jan 8, 2025 at 2:53 PM 李 秋逸 via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hello everyone. Just as the title, there is no way to test whether an experession can be ructured bound. The title not looks like a good way and maybe the best idea will come up while discussion.

At first glance this looked like P0931 "Structured bindings with polymorphic lambdas" (Aaryaman Sagar, 2017).
(If I were titling that paper, I would have called "Structured bindings in parameter declarations.")
    void get_second(auto [k,v]) { return v; }  // C++20 abbreviated template syntax
    assert(get_second(std::make_pair(1,2)) == 2);
This would also naturally apply everywhere else in the grammar that looks like a parameter list... except that it would apply only if the thing in the parameter list could take `auto`. So it wouldn't apply to `catch` parameters, and it wouldn't apply to `requires`-expression parameters, either. Which is the case you're trying to make work. So I think P0931 ends up being a red herring. (I'd still like to know what ever happened to it!)

You're aiming for something like this:
    template<class T> concept Pairish =
      requires (auto [k,v] = std::declval<T>()) { };
But requires-expression parameters aren't allowed to have default arguments. (GCC buggily accepts anyway: #99511.)
I think it's reasonable that requires-expression parameters aren't allowed to have default arguments. We should be looking for a syntax that is more general, like, "This statement is well-formed." So:
    template<class T> concept Pairish =
      requires (T t) {
        { auto [k,v] = t; }
      };
I can't think of any statement whose well-formedness it makes sense to test, except for a declaration. For example, it is silly to write
    template<class T> concept Returnable =
      requires (T t) {
        { return t; }
      };
because we can't know if `return t` is well-formed without knowing a lot about the context in which that statement appears (like, what's the return type of the function it's inside).
And constructions like `throw t` and `co_yield t` are already expressions.

There is room in the grammar here:
    template<class T> concept Pairish =
      requires (T t) {
        {{ auto [k,v] = t; }}  // notice the double braces
      };
But that's not very self-explanatory nor aesthetically appealing.

The narrowest possible feature here would be a magic compiler type-trait that tells you whether `T` can be structured-bound into n parts. (And in C++26, "into at least n parts," because there might be a trailing ellipsis.) 
This has come up on StackOverflow: https://stackoverflow.com/questions/70166429/detect-if-class-has-method-that-is-suitable-for-structured-binding
I'm convinced I recall talking about such a type-trait with Michael Park, years ago, and we designed its interface and everything... but if we did, that iteration left no trail on the Internet — no paper, no blog post, no nothing.
These days, it looks like the state of the art is Will Wray's request to compiler vendors, none of whom have acted on it yet AFAICT:
- Clang: Enhancement: Please add a builtin to count bindings in [dcl.struct.bind]
- GCC: Enhancement: Please add a builtin to count bindings in [dcl.struct.bind]
- MSVC: Enhancement: Please add a builtin to count bindings in [dcl.struct.bind]
Richard Smith suggests that you can kinda-sorta get this information in C++26 via:
auto num_bindings_impl(auto v) {
  auto [...xs] = v;
  return std::integral_constant<std::size_t, sizeof...(xs)>();
}
template<typename T> constexpr std::size_t num_bindings =
  decltype(num_bindings_impl(std::declval<T>()))::value;
But that still requires that you know the thing is decomposable into some number of parts; and it doesn't leave you in a position where you can tell what their types are.

–Arthur