2011-11-02 78 views
2

如何设计一种方法为提供给函数的每个对象调用对象方法?C++中对象列表的调用对象方法

即,

ResetAll(obj1, obj2, obj3, ...) 

将调用obj1.Reset()obj2.Reset()等..

的对象是不是在一个列表或任何其他STL容器。

+0

我假定这个函数采用的参数可变量的? (Variadic函数) – birryree

+0

我没有看到一个问题,要么通过指针将对象放入容器,要么为每个对象调用一次函数。为什么这些方法不适合你? –

+0

不幸的是我不能使用任何C++ 11功能。 – chriskirk

回答

5

也许一个可变参数模板:

template <typename ...Objs> struct Resetter; 

template <typename Obj, typename ...Rest> struct Resetter<Obj, Rest> 
{ 
    static inline void reset(Obj && obj, Rest &&... rest) 
    { 
    std::forward<Obj>(obj).Reset(); 
    Resetter<Rest...>::reset(std::forward<Rest>(rest)...); 
    } 
}; 

template <> struct Resetter<> { static inline void reset() { }; }; 

// Type-deducing helper 
template <typename ...Objs> inline void ResetAll(Objs &&... objs) 
{ 
    Resetter<Objs...>::Reset(std::forward<Objs>(objs)...); 
} 

用法:

ResetAll(ob1, obj2, some_obj, another_obj); 
+0

应该指出的是,这只适用于最新版本的编译器,因为它是全新的C++ 11标准的一部分。 –

+0

嗨@KerrekSB不幸的是,我将无法使用任何C++ 11的特定功能。你能想到其他方式吗? – chriskirk

+0

@JoachimPileborg:没错,尽管如果你喜欢,你可以使用微软技巧来模拟旧编译器上的可变参数模板(达到一定数量的固定参数)。 –

2

概念证明,因为写入可疑C++代码是有趣:

#include <vector> 
#include <iostream> 
using namespace std; 

#define Invoke(A, T,M,...)\ 
    do{\ 
     struct _{ \ 
      _& operator,(T* value){ \ 
       value->M A ; \ 
       return *this; \ 
      } \ 
     } _; _, __VA_ARGS__; \ 
    }while(0) 

#define m_a_all(...) Invoke((), Obj,m_a,__VA_ARGS__) 
#define m_b_all(...) Invoke((), Obj,m_b,__VA_ARGS__) 
#define m_c_all(A, ...) Invoke(A, Obj,m_c,__VA_ARGS__) 

class Obj{ 
public: 
    virtual void m_a(){ 
     cout << "Obj::m_a " << this << endl; 
    } 
    virtual void m_b(){ 
     cout << "Obj::m_b " << this << endl; 
    } 
    virtual void m_c(int a, double b){ 
     cout << "Obj::m_c(" << a <<"," << b<< ") " << this << endl; 
    } 
}; 
class Derived : public Obj{ 
public: 
    virtual void m_a(){ 
     cout << "Derived::m_a " << this << endl; 
    } 
    virtual void m_b(){ 
     cout << "Derived::m_b " << this << endl; 
    } 
    virtual void m_c(int a, double b){ 
     cout << "Derived::m_c(" << a <<"," << b<< ") " << this << endl; 
    } 
}; 

int main(){ 

    Obj *o1 = new Obj(), *o2 = new Obj(), *o3 = new Derived(); 

    m_a_all(o1, o2, o3); 
    cout<<endl; 
    m_a_all(o1); 
    cout<<endl; 
    m_b_all(o1, o2, o3); 
    cout<<endl; 
    m_c_all((3,42.0), o1, o2, o3); 

    return 0; 
} 

输出示例:

Obj::m_a 0x9e0a008 
Obj::m_a 0x9e0a018 
Derived::m_a 0x9e0a028 

Obj::m_a 0x9e0a008 

Obj::m_b 0x9e0a008 
Obj::m_b 0x9e0a018 
Derived::m_b 0x9e0a028 

Obj::m_c(3,42) 0x9e0a008 
Obj::m_c(3,42) 0x9e0a018 
Derived::m_c(3,42) 0x9e0a028 

链式operator,超负荷允许__VA_ARGS__使用。 一个限制是它只能在所有参数共享一个基本类型时使用,为此要调用的方法被定义。

这应该有最小的开销,不依赖于任何库。

+0

+1“因为编写可疑的C++代码很有趣”。 –

1

如果你能接受一些沉重的预处理器滥用与Boost.Preprocessor

#include <boost/preprocessor.hpp> 

#define CALL_RESET(z, n, data) BOOST_PP_CAT(p, n).Reset(); 

#define GENERATE_VARIADIC_FUNCTION(z, n, data) \ 
    template <BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(n), typename T)> \ 
    void ResetAll(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, BOOST_PP_INC(n), T, & p)) \ 
    { \ 
     BOOST_PP_CAT(BOOST_PP_REPEAT_, z)(BOOST_PP_INC(n), CALL_RESET,) \ 
    } 

/*^this generates the function 

    template <typename T0, typename T1, typename T2, ...> 
    void ResetAll(T0& p0, T1& p1, T2& p2, ...) 
    { 
     p0.Reset(); p1.Reset(); p2.Reset(); ... 
    } 

*/ 

BOOST_PP_REPEAT(BOOST_PP_LIMIT_REPEAT, GENERATE_VARIADIC_FUNCTION,) 
//^and this creates all of the above up to 256. 

例如,

#include <cstdio> 

struct Obj1 { void Reset() { printf("1\n"); } }; 
struct Obj2 { void Reset() { printf("2\n"); } }; 
struct Obj3 { void Reset() { printf("3\n"); } }; 

int main() 
{ 
    Obj1 o1; 
    Obj2 o2; 
    Obj3 o3; 
    ResetAll(o1, o2, o3, o2, o1, o3); 
    return 0; 
} 

将在屏幕上打印 '1 2 3 2 1 3'(证据:http://ideone.com/FRNvJ)。

(顺便说一句,这将在输入中的一个是一个rvalue生成错误消息的一个不可逾越的壁。)

+0

对不起没有提升,但感谢你的例子! – chriskirk