gpt4 book ai didi

c++ - 如何使用通用模板函数来处理具有不同成员的对象?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:51:05 24 4
gpt4 key购买 nike

我已经四处寻找解决方案了一段时间,但是,我可能不知道我要实现的目标的确切定义或语言语法,所以我决定发布。

我有这样的某些对象/结构:

struct A
{
char myChar;
bool hasArray = false;
};

template <uint8_t ARRAY_LEN>
struct AA : public A
{
hasArray = true;
uint8_t myArray[ARRAY_LEN];
};

我想创建一个通用函数,它可以接受这两种对象类型,并为派生的 struct AA 执行常见工作和特定工作。类似于以下内容:

template <typename T>
void func(T (&m))
{
if (T.hasArray)
{
// do some processing with m.myArray
std::cout << sizeof(m.myArray) << std::endl;
// ...
}
// common processing
std::cout << "myChar: " << m.myChar << std::endl;
};

我希望能够像这样调用函数:

A a;
AA aa;
func(a); // compiler error, this would not work as no array member
func(aa); // this works

虽然这只是一个说明我的意图的例子,但它总结了我想做的事情。实际代码要复杂得多,涉及的对象也更多。我知道我可以重载,但我想知道是否有一种方法可以用一个通用函数来实现?另请注意,我理解为什么编译器会提示示例代码我想知道是否有解决方法或我缺少的其他一些 c++ 功能。我不想做任何类型的转换......- 使用 c++11 和 GCC 4.8.5

最佳答案

这是一个相当复杂的 C++14 特性。 C++17 介绍 if constexpr使这更容易;但这是可行的。

template<std::size_t I>
using index_t=std::integral_constant<std::size_t, I>;
template<std::size_t I>
constexpr index_t<I> index{};

constexpr inline index_t<0> dispatch_index() { return {}; }
template<class B0, class...Bs,
std::enable_if_t<B0::value, int> =0
>
constexpr index_t<0> dispatch_index( B0, Bs... ) { return {}; }
template<class B0, class...Bs,
std::enable_if_t<!B0::value, int> =0
>
constexpr auto dispatch_index( B0, Bs... ) {
return index< 1 + dispatch_index( decltype(Bs){}...) >;
}

template<class...Bs>
auto dispatch( Bs... ) {
using I = decltype(dispatch_index( decltype(Bs){}... ));
return [](auto&&...args)->decltype(auto){
return std::get<I::value>( std::make_tuple(decltype(args)(args)..., [](auto&&...){}) );
};
}

dispatch( some_test )返回一个采用 auto&&... 的 lambda .如果 some_test,它又返回第一个参数是类真类型,第二个参数(或 [](auto&&...){} 如果没有第二个参数)如果 some_test属于假类。

然后我们编写代码来检测您的 myArray .

namespace details {
template<template<class...>class Z, class=void, class...Ts>
struct can_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = typename details::can_apply<Z, void, Ts...>::type;

template<class T>
using myArray_type = decltype( std::declval<T>().myArray );

template<class T>
using has_myArray = can_apply< myArray_type, T >;

has_myArray<T>如果T 是真实的有成员(member).myArray .

我们把它们连接起来

dispatch( has_myArray<T>{} )(
[&](auto&& m) {
// do some processing with m.myArray
std::cout << sizeof(m.myArray) << std::endl;
// ...
}
)( m );

现在当且仅当 m.myArray 时,中间的 lambda 才会运行有效。

可以编写更复杂的测试,不仅检查是否存在,但通常以上内容就足够了。

在像 MSVC 2015 这样的非 C++11 编译器中,替换

std::enable_if_t<B0::value, int> =0

std::enable_if_t<!B0::value, int> =0

class = std::enable_if_t<B0::value>

class = std::enable_if_t<!B0::value>, class=void

分别。是的,这些更丑陋。去和 MSVC 编译器团队谈谈。

如果您的编译器缺少 C++14,则您必须自己编写 void_t或者写你自己的 enable_if_t或使用丑陋的更长版本 enable_if .

此外,模板变量index在 C++11 中是非法的。替换 index<blah>index_t<blah>{} .

缺少auto&& lambdas 使上述非常痛苦;您可能必须将 lambda 转换为外联函数对象。然而,自动 lambda 是人们实现的第一个 C++14 功能,通常在他们完成 C++11 之前。

以上代码设计合理,但可能有错别字。

关于c++ - 如何使用通用模板函数来处理具有不同成员的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41945467/

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