使用结构化绑定的“反射”

Yam*_*ari 7 c++ c++20

我想知道是否可以使用以下事实

struct Foo
{
    int x;
};

int main()
{
    Foo foo;
    auto [a0] = foo; 
    auto [a1, b1] = foo;
    auto [a2, b2, c2] = foo;
    // auto [a, b, c, ...] = foo;
}
Run Code Online (Sandbox Code Playgroud)

只有第一个结构化绑定是有效的,以便创建接受任何 pod 类型并返回由传递的 pod 的所有成员类型组成的元组,例如,对于 Foo 它将返回

std::tuple<int>
Run Code Online (Sandbox Code Playgroud)

我试过这样的事情,但没有奏效:

#include <tuple>
#include <type_traits>
#include <utility>

using namespace std;

template<typename T, typename U = void>
struct to_tuple;

template<typename T>
struct to_tuple<T, void_t<decltype([](T x) {
        auto [a] = x;
        return make_tuple(a);
    }(declval<T>()))>>
{
    using type = decltype([](T x) {
        auto [a] = x;
        return make_tuple(a);
    }(declval<T>()));
};

template<typename T>
struct to_tuple<T, void_t<decltype([](T x) {
        auto [a, b] = x;
        return make_tuple(a, b);
    }(declval<T>()))>>
{
    using type = decltype([](T x) {
        auto [a, b] = x;
        return make_tuple(a, b);
    }(declval<T>()));
};

template<typename T>
using to_tuple_t = typename to_tuple<T>::type;

struct Bar1
{
    int x;
};

struct Bar2
{
    int x;
    float y;
};

int main()
{
    static_assert(is_same_v<to_tuple_t<Bar1>, tuple<int>>);
    static_assert(is_same_v<to_tuple_t<Bar2>, tuple<int, float>>);
}
Run Code Online (Sandbox Code Playgroud)

And*_*dyG 4

这里的主要问题是结构化绑定声明就是一个声明。我们无法形成“结构化绑定表达式”来获取类型,这是元编程中约束模板所需的类型(例如,模式void_tconcept/requires子句)


根据[dcl.struct.bnd],尽管存在赋值表达式,但结构化绑定显然是一个声明

模板元编程依赖于types,并且声明没有类型。例如,您不能说decltype(int a = 10)或什至decltype(int a)出于这个原因。

可以decltype(int{})因为现在我们有一个表达式。因此,您的void_t模式不起作用。

不幸的是,概念/约束对我们没有帮助,因为我们不能在 require 子句中进行声明(根据[gram.expr]


就我个人而言,我认为这是一个疏忽,我们无法拥有int{}与结构化绑定相同的功能。但话又说回来,反思无论如何都在进行中,所以这一点可能没有实际意义。

编辑:正如dfri 指出的那样,有一个称为语句表达式的 GNU 扩展可以使这成为可能(作为扩展,它是可以理解的不可移植代码)