gpt4 book ai didi

c++ - 使用 "static virtual"函数的元对象

转载 作者:太空狗 更新时间:2023-10-29 22:58:49 24 4
gpt4 key购买 nike

我在项目中开发了某种元对象机制,以便将任何类型的类型名称和属性关联到对象(参见结果 here )。我有一个肮脏的代码在工作,我正试图让它更干净。给定以下虚拟结构:

struct A
{
using Self = A;
using Base = void;

static std::string get_type_name(){ return { "A" }; }

static std::vector<int> get_properties(){ return { 0 }; }
};

#define SELF(class_name)\
using Base = Self;\
using Self = class_name;

struct AA : A
{
SELF(AA)

static std::string get_type_name() { return { "AA" }; }
};

struct AAA : AA
{
SELF(AAA)

static std::string get_type_name(){ return { "AAA" }; }

static std::vector<int> get_properties(){ return { 2, 1 }; }
};

我最终使用这段代码来获取对象在其层次结构中的类型名称:

// when the type has no Base member:
template<
typename T,
typename std::enable_if<std::is_same<typename T::Base, void>::value>::type* = nullptr
>
typename std::vector<decltype(T::Self::get_type_name())> get_type_names()
{
return { T::Self::get_type_name() };
}

// when the type has a Base member:
template<
typename T,
typename std::enable_if<!std::is_same<typename T::Base, void>::value>::type* = nullptr
>
typename std::vector<decltype(T::Self::get_type_name())> get_type_names()
{
auto data = get_type_names<typename T::Base>();
data.insert(data.begin(), T::Self::get_type_name());
return data;
}

还有类似的属性:

template<
typename T,
typename std::enable_if<std::is_same<typename T::Base, void>::value>::type* = nullptr
>
decltype(T::Self::get_properties()) get_properties()
{
return { T::Self::get_properties() };
}

template<
typename T,
typename std::enable_if<!std::is_same<typename T::Base, void>::value>::type* = nullptr
>
decltype(T::Self::get_properties()) get_properties()
{
auto data = get_properties<typename T::Base>();
auto self_data = T::Self::get_properties();
data.insert(data.begin(), self_data.begin(), self_data.end());
return data;
}

使用此代码段测试代码时:

template<typename T>
void print()
{
std::cout << T::get_type_name() << std::endl << "\thas types:" << std::endl;
for(auto type_name : get_type_names<T>())
{
std::cout << "\t\t" << type_name << std::endl;
}
std::cout << "\thas properties:" << std::endl;
for(auto property : get_properties<T>())
{
std::cout << "\t\t" << property << std::endl;
}
}

int main()
{
print<A>();
print<AA>();
print<AAA>();

return 0;
}

我得到以下输出:

A
has types:
A
has properties:
0
AA
has types:
AA
A
has properties:
0
0
AAA
has types:
AAA
AA
A
has properties:
2
1
0
0

第一个原型(prototype)适用于名称,但是一旦声明了一个没有属性的对象,其基类中的属性就会被复制。有人看到了解决问题的简单方法吗?

奖励问题:元函数的实现非常相似,有人提示我如何分解代码吗?

完整的实例可用here

最佳答案

这是一个不完整的解决方案,可以让您走上正轨。首先,一切都取决于遍历基地名单。因此,让我们将其考虑到它自己的元函数中:

template <class... > struct typelist { };

template <class T, class... Bases>
struct get_bases
: get_bases<typename T::Base, Bases..., T>
{ };

template <class... Bases>
struct get_bases<void, Bases...>
{
using type = typelist<Bases...>;
};

template <class T>
using get_bases_t = typename get_bases<T>::type;

现在,get_bases_t<A>typelist<A>get_bases_t<AAA>typelist<AAA, AA, A> .现在,您所有的其他功能都只是基于沿着该类型列表走下去并对其进行操作。所以让我们添加一个简单的方法来做到这一点:

template <class T> struct tag { using type = T; };

template <class... Ts>
auto for_each(typelist<Ts...>) {
return [](auto&& f){
using swallow = int[];
(void)swallow{0,
(void(f(tag<Ts>{})), 0)...
};
};
}

现在,获取所有属性就是将所有碱基转换为对应的 get_properties() 的问题函数,然后调用所有唯一的函数。您可能可以在编译时挑选出独特的功能,但这也适用:

template <class T>
std::vector<int> get_properties() {
using bases = get_bases_t<T>;

using F = std::vector<int>(*)();
F last = nullptr;
std::vector<int> props;

for_each(bases{})([&](auto t){
using B = typename decltype(t)::type;
F cur = B::get_properties;
if (cur != last) {
auto next = cur();
props.insert(props.end(), next.begin(), next.end());
last = cur;
}
});

return props;
}

这种方法对于获取类型名称也非常简单:

template <class T>
std::vector<std::string> get_type_names()
{
using bases = get_bases_t<T>;

std::vector<std::string> names;
names.reserve(len_v<bases>); // TODO

for_each(bases{})([&](auto t){
names.push_back(decltype(t)::get_type_name());
});

return names;
}

或者,在这种情况下,只需:

template <class... Bs>
std::vector<std::string> get_type_names_impl(typelist<Bs...>) {
return {Bs::get_type_name()...};
}


template <class T>
std::vector<std::string> get_type_names()
{
return get_type_names_impl(get_bases_t<T>);
}

关于c++ - 使用 "static virtual"函数的元对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39274948/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com