C++ 如何使用通用模板函数处理具有不同成员的对象?
我已经四处寻找了一段时间来解决这个问题,但是,我可能不知道我试图实现的确切定义或语言语法,所以我决定发布 我有如下某些对象/结构:C++ 如何使用通用模板函数处理具有不同成员的对象?,c++,c++11,templates,C++,C++11,Templates,我已经四处寻找了一段时间来解决这个问题,但是,我可能不知道我试图实现的确切定义或语言语法,所以我决定发布 我有如下某些对象/结构: struct A { char myChar; bool hasArray = false; }; template <uint8_t ARRAY_LEN> struct AA : public A { hasArray = true; uint8_t myArray[ARRAY_LEN]; }; 我希望能够像这样调用函数: A a;
struct A
{
char myChar;
bool hasArray = false;
};
template <uint8_t ARRAY_LEN>
struct AA : public A
{
hasArray = true;
uint8_t myArray[ARRAY_LEN];
};
我希望能够像这样调用函数:
A a;
AA aa;
func(a); // compiler error, this would not work as no array member
func(aa); // this works
虽然这只是一个说明我意图的例子,但它总结了我想做的事情。实际的代码要复杂得多,涉及到更多的对象。我知道我可以重载,但我想知道是否有一种方法可以用一个泛型函数来实现它?还请注意,我理解编译器为什么用示例代码来抱怨,我想知道是否有一个解决方案或其他我丢失的C++功能。我不想做任何类型的铸造。。。
-使用c++11和GCC4.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&&...){}) );
};
}
而has_myArray
是真的,就像T
有一个成员.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 >;
我们把这些钩在一起
dispatch( has_myArray<T>{} )(
[&](auto&& m) {
// do some processing with m.myArray
std::cout << sizeof(m.myArray) << std::endl;
// ...
}
)( m );
及
std::在t=0时启用
与
class=std::启用
及
class=std::启用,如果,class=void
分别。是的,这些更难看。去和MSVC编译器团队谈谈
如果您的编译器缺少C++14,则必须编写自己的void\u t
,或者编写自己的enable\u If\u t
,或者使用enable\u If
使用难看的较长版本
此外,模板变量index
在C++11中是非法的。将索引
替换为索引{}
缺少auto&
lambdas使上述情况非常痛苦;您可能需要将lambda转换为一个越界函数对象。然而,auto lambdas是最早的C++14功能之一,通常是在完成C++11之前实现的
上面的代码是实体设计的,但可能包含打字错误
有一种方法可以用一个泛型函数来实现吗
我不这么认为,因为如果在这个函数中插入一个sizeof(m.myArray)
,则不能使用没有myArray
成员的类型调用它。即使它在代码的某个部分(运行时)没有执行,因为编译器需要编译它
但是,如果我理解正确,您的hasArray
会说您的结构是否有myArray
成员。因此,我假设您可以在静态constexpr
成员中对其进行转换,如下所示
struct A
{
static constexpr bool hasArray { false };
char myChar { 'z' };
};
template <uint8_t ARRAY_LEN>
struct AA : public A
{
static constexpr bool hasArray { true };
uint8_t myArray[ARRAY_LEN];
};
现在您可以使用这两种类型调用func()
int main()
{
A a;
AA<12U> aa;
func(a); // print myChar: z
func(aa); // print 12, myChar: z
}
intmain()
{
A A;
AA;
func(a);//打印myChar:z
func(aa);//打印12,myChar:z
}
记住要包括
type\u traits
和iostream
如果您不想修改实例,重载在您的情况下可以正常工作:
#include<iostream>
#include<cstdint>
struct A
{
char myChar;
};
template <uint8_t ARRAY_LEN>
struct AA : public A
{
uint8_t myArray[ARRAY_LEN];
};
void func(const A &m)
{
std::cout << "myChar: " << m.myChar << std::endl;
};
template <uint8_t AL>
void func(const AA<AL> &m)
{
std::cout << sizeof(m.myArray) << std::endl;
func(static_cast<const A &>(m));
}
int main() {
func(A{});
func(AA<1>{});
}
#包括
#包括
结构A
{
char-myChar;
};
模板
结构AA:公共A
{
uint8_t myArray[ARRAY_LEN];
};
无效函数(常数A&m)
{
St::CUT直到C++ 17,在一个函数内没有办法。如果使用“代码”> HasyMyLaule特性,语句可以使这一点生效。@ 0x499 602D2,这是C++。
class = std::enable_if_t<B0::value>
class = std::enable_if_t<!B0::value>, class=void
struct A
{
static constexpr bool hasArray { false };
char myChar { 'z' };
};
template <uint8_t ARRAY_LEN>
struct AA : public A
{
static constexpr bool hasArray { true };
uint8_t myArray[ARRAY_LEN];
};
template <typename T>
void func2 (T const & m, std::true_type const &)
{ std::cout << sizeof(m.myArray) << ", "; }
template <typename T>
void func2 (T const &, std::false_type const &)
{ }
template <typename T>
void func(T (&m))
{
func2(m, std::integral_constant<bool, T::hasArray>{});
// common processing
std::cout << "myChar: " << m.myChar << std::endl;
}
int main()
{
A a;
AA<12U> aa;
func(a); // print myChar: z
func(aa); // print 12, myChar: z
}
#include<iostream>
#include<cstdint>
struct A
{
char myChar;
};
template <uint8_t ARRAY_LEN>
struct AA : public A
{
uint8_t myArray[ARRAY_LEN];
};
void func(const A &m)
{
std::cout << "myChar: " << m.myChar << std::endl;
};
template <uint8_t AL>
void func(const AA<AL> &m)
{
std::cout << sizeof(m.myArray) << std::endl;
func(static_cast<const A &>(m));
}
int main() {
func(A{});
func(AA<1>{});
}
#include<iostream>
#include<cstdint>
struct A
{
char myChar;
};
template <uint8_t ARRAY_LEN>
struct AA : public A
{
uint8_t myArray[ARRAY_LEN];
};
void func(A &m)
{
std::cout << "myChar: " << m.myChar << std::endl;
}
template <typename T>
auto func(T &m) -> decltype(m.myArray, void())
{
std::cout << sizeof(m.myArray) << std::endl;
A &a = m;
func(a);
}
int main() {
AA<1> aa{};
A a{};
func(a);
func(aa);
}