我正在编写用于结构自动反射的简单代码。简而言之,每个结构都有带有名称和成员指针的静态元组,代码使用 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 函数的多种组合,但都没有用。
我试过了:
下面提取了完整的想法示例。和编译器资源管理器链接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>;
}
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);
};