为具有对象或对象数组作为成员的类运行不同的代码

时间:2014-02-22 12:48:34

标签: c++ templates template-meta-programming

我有一个将对象作为参数

的方法
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功能的情况下做到这一点?

3 个答案:

答案 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()版本。