有没有办法获得一个类的字段数?
SELECT
a.KeyField, a.AlphaValue AS Compostable
INTO
#DAT
FROM
[SysproCompanyA].[dbo].AdmFormData a
WHERE
a.FieldName = 'DAT001'
SELECT
b.KeyField, b.AlphaValue AS Trial
INTO
#PAS
FROM
[SysproCompanyA].[dbo].AdmFormData b
WHERE
b.FieldName = 'PAS001'
SELECT
c.KeyField AS JobNumber, c.Compostable, d.Trial
FROM
#DAT c
INNER JOIN
#PAS d ON c.KeyField = d.KeyField
WHERE
c.KeyField = '00170579'
DROP TABLE #DAT
DROP TABLE #PAS
我已经找到了this question但它已经过时了 - 我希望可以用C ++ 14/17拼接一些东西(毕竟我们现在有类似magic_get的东西 - 也许它的一些子集......?)
编辑: - 编译器挂钩也可以工作,即使它仅适用于MSVC或GCC或Clang - 我使用全部3。
答案 0 :(得分:7)
你不能这样做(开箱即用),因为C ++中还没有反映(还)。您需要探索其他选项,例如第三方库。
答案 1 :(得分:5)
事实上,Antony Polukhin向我们展示了C ++ 有(某些)反射,因为C ++ 14,而不知道它;并且您可以提取有关字段的信息。 ......好吧,至少对于普通的数据结构/类。观看他的CppCon 2016演讲:
C++14 Reflections Without Macros, Markup nor External Tooling / Antony Polukhin
然后你写道:
template <class T, std::size_t I0, std::size_t... I>
constexpr auto detect_fields_count(std::size_t& out, std::index_sequence<I0, I...>)
-> decltype( T{ ubiq_constructor<I0>{}, ubiq_constructor<I>{}... } )
{ out = sizeof...(I) + 1; /*...*/ }
template <class T, std::size_t... I>
constexpr void detect_fields_count(std::size_t& out, std::index_sequence<I...>) {
detect_fields_count<T>(out, std::make_index_sequence<sizeof...(I) - 1>{});
}
可以获得字段数。当然,您还需要巧妙构思的ubiq
结构。您实际需要使用的是这两个文件:
https://github.com/apolukhin/magic_get/blob/develop/include/boost/pfr/detail/config.hpp
https://github.com/apolukhin/magic_get/blob/develop/include/boost/pfr/detail/fields_count.hpp
这应该足够了。
答案 2 :(得分:0)
这是einpoklum的答案的修改版本:
template <size_t I>
struct ubiq_constructor
{
template <typename Type>
constexpr operator Type&() const noexcept
{
return Type(*this);
}
};
template <size_t fields, class POD>
struct fields_count
{
constexpr static size_t count = fields;
typedef POD type;
};
// why use size_t& in the constexpr function in the first place?
template <class T, size_t I0, size_t ... I>
constexpr auto fields_total(const std::index_sequence<I0, I...>&)
-> fields_count<sizeof...(I) + 1, decltype(T{ ubiq_constructor<I0>(), ubiq_constructor<I>()...})>
{
return fields_count<sizeof...(I) + 1, decltype(T{ ubiq_constructor<I0>(), ubiq_constructor<I>()... })>();
}
template <class T, size_t ... I>
constexpr auto fields_total(const std::index_sequence<I...>&)
{
return fields_total<T>(std::make_index_sequence<sizeof...(I) - 1>());
}
//use this for convinience to return number of fields at compile time
template <class T>
constexpr size_t fields_total(const T&)
{
auto counted = fields_total<T>(std::make_index_sequence<sizeof(T) / sizeof(char)>());
return decltype(counted)::count;
}
另外,在CppCon 2016视频中提到的获取文件类型的方法在我看来似乎相当困难,而且据我所知,这取决于BOOST库。
因此,这是获取提供的类的类型的元组的完整代码(假设它没有私有或受保护的非静态数据成员,用户定义/提供的构造函数等。请参见aggregate initialization以供参考)
#include <tuple>
template <size_t I>
struct ubiq_constructor
{
template <typename Type>
constexpr operator Type&() const noexcept
{
return Type(*this);
}
};
template <size_t fields, class POD>
struct fields_count
{
constexpr static size_t count = fields;
typedef POD type;
};
template <class T, size_t I0, size_t ... I>
constexpr auto fields_total(const std::index_sequence<I0, I...>&)
-> fields_count<sizeof...(I) + 1, decltype(T{ ubiq_constructor<I0>(), ubiq_constructor<I>()...})>
{
return fields_count<sizeof...(I) + 1, decltype(T{ ubiq_constructor<I0>(), ubiq_constructor<I>()... })>();
}
template <class T, size_t ... I>
constexpr auto fields_total(const std::index_sequence<I...>&)
{
return fields_total<T>(std::make_index_sequence<sizeof...(I) - 1>());
}
template <class T>
constexpr size_t fields_total(const T&)
{
auto counted = fields_total<T>(std::make_index_sequence<sizeof(T) / sizeof(char)>());
return decltype(counted)::count;
}
template <class allowed>
struct ubiq_explicit
{
template <class other>
constexpr operator other&() = delete;
constexpr operator allowed&() noexcept;
};
template <class owner, class field>
struct owner_field
{
typedef field type;
};
template <class T, class cur, template <class ...> class pack, class ... prev>
constexpr auto guess_field(const T&, const cur&, const pack<prev...>&) noexcept
->owner_field<decltype(T{ prev() ... , ubiq_explicit<cur>() }), cur >
{
return owner_field<decltype(T{ prev() ... , ubiq_explicit<cur>() }), cur > ();
}
// if substitution fails
template <class T, class cur, class pack>
constexpr auto guess_field(const T&, const cur&, const pack&) noexcept
{
return owner_field<T, void>();
}
template <class T, class cur, class pack>
class is_field
{
using interm = decltype(guess_field(T(), cur(), pack()));
public:
constexpr static bool value = !std::is_same_v<owner_field<T, void>, interm>;
};
//function to detect if a given class at given position is same as an original field
template <class T, class cur /*type at current position*/, class pack /*previous types*/>
constexpr bool is_field_v(const T&, const cur&, const pack&) noexcept
{
if constexpr (std::is_same_v<owner_field<T, void>, decltype(guess_field(T(), cur(), pack()))>)
return false;
else return true;
}
#include <string>
typedef std::tuple<bool,
char, unsigned char,
short, unsigned short,
int, unsigned int,
long, unsigned long,
long long, unsigned long long,
float, double, long double, long double
/* std::string will not compile as not constexpr*/> pod_map;
//traverse given map!
template <size_t indx>
using pod_elem = std::remove_reference_t<decltype(std::get<indx>(pod_map()))>;
template <template <class ... > class pack, class ... args>
constexpr size_t args_count(const pack<args...>&) noexcept
{
return sizeof...(args);
}
template <size_t curr_iter, class T, class prev_pack, template <class ...> class types_map, class ... types>
constexpr auto traverse_map(T, prev_pack, types_map<types...>) noexcept
{
static_assert(curr_iter < args_count(types_map<types...>()), "Failed to traverse types map! Check if type is registered in the map!");
if constexpr (!is_field_v(T(), pod_elem<curr_iter>(), prev_pack()))
return traverse_map<curr_iter + 1>(T(), prev_pack(), types_map<types...>());
else return owner_field<T, pod_elem<curr_iter>>();
}
template <class T, class t_map, class ... prev_fields>
constexpr auto get_fields(T, t_map, prev_fields...)
{
//guess cur_field
auto found = traverse_map<0>(T(), std::tuple<prev_fields...>(), t_map());
if constexpr (sizeof...(prev_fields) < fields_total(T()) - 1)
return get_fields(T(), t_map(), prev_fields()..., decltype(found)::type());
//bottom level
else
return std::make_tuple(prev_fields()..., decltype(found)::type());
}
struct abc
{
int a;
float b;
char c, d;
int e;
double f;
};
int main(int argc, char** argv)
{
//checking that intermediate functions work
ubiq_explicit<int> ub_int;
//abc{ ubiq_explicit<int>() };
//abc{ ubiq_explicit<double>() }; will not compile!
is_field_v(abc(), int(), std::tuple<>()); // works, valid
is_field_v(abc(), float(), std::tuple<int>()); // works, valid
is_field_v(abc(), char(), std::tuple<int, float>()); // works, valid
is_field_v(abc(), double(), std::tuple<int, float>()); // invalid
traverse_map<0>(abc(), std::tuple<>(), pod_map());
traverse_map<0>(abc(), std::tuple<int>(), pod_map());
traverse_map<0>(abc(), std::tuple<int, float>(), pod_map());
// traverse_map<0>(abc(), std::tuple<int, float, char>(), pod_map()); //will not compile
fields_total<abc>(std::make_index_sequence<10>());
fields_total(abc());
// decltype using aggregate initialization with explicit conversion of the arguments
owner_field<decltype(abc{ ubiq_explicit<int>() }), int > f0{};
owner_field<decltype(abc{ int(), ubiq_explicit<float>() }), float > f1{};
owner_field<decltype(abc{ int(), float(), ubiq_explicit<char>() }), char > f2{};
auto igi0 = guess_field(abc(), int(), std::tuple<>());
auto igi1 = guess_field(abc(), float(), std::tuple<int>());
auto igi2 = guess_field(abc(), char(), std::tuple<int, float>());
auto igi99 = guess_field(abc(), double(), std::tuple<int, float>());
//returns tuple
get_fields(abc(), pod_map());
return 0;
}