我有一个将对象作为参数
的方法void fun(const Obj& obj)
Obj
可以通过两种不同的方式定义:
struct Obj
{
Type x;
};
和
struct Obj
{
Type x[42];
};
我无法修改Obj
的定义(即我无法重命名类)。此外,我无法修改fun
的签名,我宁愿不在fun
内使用预处理程序指令。有没有办法使用元编程来编译和工作,无论包含Obj
的哪个定义:
void fun(const Obj& obj)
{
impl(obj); // executes some code if obj.x is an object
// executes some other code if obj.x is an array
}
?有没有办法在没有C ++ 11功能的情况下做到这一点?
答案 0 :(得分:2)
您可以根据decltype(obj.x)
选择模板的专业化:
template<typename T>
void impl(const Obj&);
template<>
void impl<Type>(const Obj&) {}
template<>
void imp<Type[42]>(const Obj&) {}
void fun(const Obj& obj)
{
impl<decltype(obj.x)>(obj);
}
可能的C ++ 03方式是检查Type Obj::x
是否存在的成员检测器特征类。这一次,impl
的模板参数为bool
,因此您只需传递检查结果:
template<typename C>
struct has_Type_x {
template<typename U, U>
struct Check;
typedef char(&yes)[1];
typedef char(&no)[2];
template<typename> static no test(...);
template<typename U> static yes test(Check<Type U::*, &U::x>*);
static const bool value = sizeof(test<C>(0)) == sizeof(yes);
};
template<bool> void impl(const Obj&);
template<>
void impl<true>(const Obj&) {}
template<>
void impl<false>(const Obj&) {
std::cout << "arr";
}
void fun(const Obj& obj)
{
impl< has_int_x<Obj>::value >(obj);
}
答案 1 :(得分:1)
这可以通过对实现函数fun_impl
的第二次调用来完成,该函数也将obj.x
作为参数。此函数通过两个重载专门用于标量或数组,后者接受对数组的引用,因此也保持数组大小:
template <typename Obj, typename T>
void fun_impl(const Obj& obj, const T& x) {}
template <typename Obj, typename T, size_t N>
void fun_impl(const Obj& obj, const T (&x)[N]) {}
template <typename Obj>
void fun(const Obj& obj)
{
fun_impl(obj, obj.x);
}
这适用于C ++ 03,不需要任何特征功能或SFINAE。另请参阅live example,其余部分使用C ++ 11以方便使用。
如果obj
仅包含x
,您可以将其作为参数从fun_impl
中删除。我把它留在这里是为了更为一般的情况,其中obj
也可能有其他成员。
请注意,此处fun
本身作为模板提供;我想这是你需要做的事情,因为你正在处理Obj
的不同定义。
答案 2 :(得分:0)
我的建议是使用函数重载。在您的情况下,您不需要元编程/模板:
void fun(const Obj& obj)
{
impl(obj.x);
}
void impl(const Type& x){...}
void impl(Type x[]){...}
如果Obj::x
被声明为Type x
,则会调用第一个impl()
版本。同样在另一种情况下,将调用第二个impl()
版本。