可以编写需要迭代静态元组并检查每个元组项的概念

问题描述 投票:0回答:1

我正在编写用于结构自动反射的简单代码。简而言之,每个结构都有带有名称和成员指针的静态元组,代码使用 std::apply 对其进行迭代并做一些事情。


struct TestRecord{
    int id;
    long counter; 
};

template<>
struct RepositoryHelperID<TestRecord>
{
    static constexpr auto members = [] {
        return std::make_tuple(
            std::make_tuple("id"sv, &TestRecord::id),
            std::make_tuple("counter"sv, &TestRecord::counter));
    }();
};

它正在工作,但我为整个代码工作所需的每种类型的成员提供了一些辅助函数 (getDBType)。为了在缺少此辅助函数的情况下最大限度地减少编译错误大小,我决定创建一个概念,它应该:

  • 迭代静态元组
  • 从元组元素中获取成员类型
  • 检查此类型是否存在特定功能。

但我无法让它工作。如果所有函数都存在,则代码可以编译并且可以工作。当函数缺失时,我希望这个概念没有实现,但我有关于缺失函数的编译错误。我假设如果缺少功能,则要求不满足并且概念失败,但据我推断,需要评估模板功能然后检查要求声明。我在 std::apply 中尝试了 lambda 函数的多种组合,但都没有用。

我试过了:

  • 带有 require 和空体的 lambda
  • 根据预期要求制作更简单的跳跃功能。

下面提取了完整的想法示例。和编译器资源管理器链接https://godbolt.org/z/zss8aTM13

问题是是否可以使用元组和 std::apply 来创建概念。

#include <array>
#include <iostream>
#include <tuple>

#include <string_view>
using namespace std::string_view_literals;

template <std::same_as<int> T>
std::string getDBType(){
    return "int";
}

template <std::same_as<double> T>
std::string getDBType(){
    return "double";
}

template<typename T>
struct RepositoryHelperID
{

};

struct TestRecord{
    int id;
    long counter; // change to double to compile 
};


template<>
struct RepositoryHelperID<TestRecord>
{
    static constexpr auto members = [] {
        return std::make_tuple(
            std::make_tuple("id"sv, &TestRecord::id),
            std::make_tuple("counter"sv, &TestRecord::counter));
    }();
};
template <typename T>
concept HaveGetType =
    requires {
        {
            getDBType<T>()
        };
    };



template <typename T>
concept RepositoryHelperConcept =
    requires(T) {
        {
            RepositoryHelperID<T>::members
        };
        {
            // std::remove_reference_t<decltype(std::declval<T>().*std::get<1>(args))> == int , double etc. so check if eg. getDBType<int>() exists
              std::apply([](auto&&... args) {
                 ((getDBType<std::remove_reference_t<decltype(std::declval<T>().*std::get<1>(args))>>()), ...);
            },
                RepositoryHelperID<T>::members)
            
        };
    };

int main(){
    ///static_assert(!RepositoryHelperConcept<TestRecord>);
    return !RepositoryHelperConcept<TestRecord>;  
}
c++ tuples apply c++20 c++-concepts
1个回答
0
投票

std::apply
是一个不受约束的函数,因此当传入的 lambda 格式错误时,
requires
子句总是会触发硬错误。

但是,仍然可以使用

std::apply
检查每个成员指针被对象调用后的返回类型是否满足
HaveGetType

template <typename T>
concept HaveGetType = requires {
  getDBType<T>();
};

template <typename T>
concept RepositoryHelperConcept = requires {
  RepositoryHelperID<T>::members;
  requires std::apply([](auto&&... args) {
    return (
      HaveGetType<
        std::remove_reference_t<decltype(std::declval<T>().*std::get<1>(args))>
      > && ...);
  }, RepositoryHelperID<T>::members);
};

演示

© www.soinside.com 2019 - 2024. All rights reserved.