c++ - 如何编写结构化绑定(bind)的概念?

标签 c++ gcc c++-concepts

编译以下(精简)代码时:

#include <tuple>
#include <stdlib.h>

template<size_t N> struct tying;
template<> struct tying<1> {static auto function(auto& o) -> decltype(auto) {auto& [p1]    = o;return std::tie(p1);}};
template<> struct tying<2> {static auto function(auto& o) -> decltype(auto) {auto& [p1,p2] = o;return std::tie(p1,p2);}};

template<typename T, size_t N> concept bool n_components =
requires(T& object) {
    { tying<N>::function(object) };
};

typedef struct
{
    int   a;
    float b;
} test_t;

int main(int argc, char* argv[])
{
    constexpr size_t n = 1;
    constexpr bool   t = n_components<test_t, n>;

    printf("n_components<test_t, %d>: %s\n", n, t ? "yes" : "nope");
    return 0;
}

使用 gcc 特定选项 -std=c++1z -fconcepts gcc(版本 7.3.0,以及 godbolt 的 x86-64 gcc-trunk 也)失败并出现错误:

error: only 1 name provided for structured binding
note: while 'test_t' decomposes into 2 elements

我对此感到非常惊讶,因为错误在 requires-expression 中“引发” ,据我了解,这应该导致 n_components约束条件被评估为 false,因为不满足要求。

注意:替换constexpr size_t n = 1;使用其他值“修复”错误,所以我假设 n_components约束不是罪魁祸首:

  • 替换为 n = 2 n_components约束按预期评估为“真”。
  • 替换为 n = 3 n_components约束按预期计算为“false”——由于引用了未专门化的 tying<3>结构。

似乎还没有其他支持 c++ 概念和结构化绑定(bind)的编译器可供比较。

附言。我在玩“穷人的反射(reflection)”又名 magic_get并希望取代不可靠的 is_braces_constructible具有更强大的特性......

最佳答案

这是自 5.0 以来 clang 的部分解决方案。
它是从最近的 reddit 帖子中提炼出来的 Find the number of structured bindings for any struct

该方法是非标准的,使用 gnu 扩展语句表达式 来有效地对结构化绑定(bind)声明进行 SFINAE。它也是不可移植的,因为 gcc 无法解析 lambda 尾随返回类型中语句表达式中的结构化绑定(bind)。

template <typename... Ts> struct overloads : Ts... { using Ts::operator()...; };
template <typename... Ts> overloads(Ts...) -> overloads<Ts...>;

template <typename T>
auto num_bindings_impl() noexcept {
    return overloads{
        [](auto&& u, int) -> decltype(({auto&& [x0] = u; char{};}))(*)[1] {return {};},
        [](auto&& u, int) -> decltype(({auto&& [x0,x1] = u; char{};}))(*)[2] {return {};},
        [](auto&& u, int) -> decltype(({auto&& [x0,x1,x2] = u; char{};}))(*)[3] {return {};},
        [](auto&& u, int) -> decltype(({auto&& [x0,x1,x2,x3] = u; char{};}))(*)[4] {return {};},
        [](auto&& u, unsigned) -> void {}
    }(declval<T>(), int{});
};

此实现仅用于未评估的上下文并扩展
对于任意数量的绑定(bind),直到编译器实现限制。

然后,您可以定义达到该限制的特征:

template <typename T>
inline constexpr bool has_bindings = [] {
    if constexpr ( ! is_empty_v<T> )
        return ! is_void_v< decltype(num_bindings_impl<T>()) >;
    else return false;
}();

template <typename T>
inline constexpr unsigned num_members = [] {
    if constexpr ( ! is_empty_v<T> )
        return sizeof *num_bindings_impl<T>();
    else return 0;
}();

https://godbolt.org/z/EVnbqj

关于c++ - 如何编写结构化绑定(bind)的概念?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49340829/

相关文章:

c - 用 C 链接到一个特定的库

编译 mathgl C 示例

c++ - 为什么在生成的模板中重复了特定的概念约束?

c++ - 约束类模板函数以接受特定的 POD 类型

c++ - 如果可以对数组执行相同的操作,堆栈的用途是什么?

c++ - 愚蠢的 C++ 语法尚未声明

c++ - c/c++中VARNAME_T和VARNAME_P有什么区别

c++ - move 语义将如何改进 "my way"?

c++ - 使用 gcc 构建 C++ 的推荐 -W 标志

c++ - 嵌入模板时模板化函数类型丢失