templates and abstrace classes

Hi,
I am trying to write a very general code that serves sort of as a framework for doing some task
My code has 2 classes class1 and class2. class1 and class2 are to be implemented by user using any 5 data type based on his need later on.

I have defined class 1 is a template abstract class:
1
2
3
4
5
6
7
8
template<typename T1, typename T2, typename T3, typename T4, typename T5>
class class : public ns3::Object
{
public:
	class1();
	virtual ~class1();
	virtual T1 GetState(T2,T3,T4,T5);
};


class2 is an abstract class that needs to have a pointer to an instance of calss1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class class2 : public ns3::Object
{
public:
    
    template<typename T1,typename T2,typename T3,typename T4,typename T5>
    void SetClass1Ptr(class1<T1,T2,T3,T4,T5>*);
    
    template<typename T1,typename T2,typename T3,typename T4,typename T5>
    class1<T1,T2,T3,T4,T5>* GetClass1Ptr();

private:
       template<typename T1,typename T2,typename T3,typename T4,typename T5>
       struct Class1Ptr
   	{
    	   class1<T1,T2,T3,T4,T5 >* class1Ptr ;
        } m_class1Ptr;
}


now my questions are:
1- is this the right way of doing this task?
2- how should the functins SetClass1Ptr and GetClass1Ptr be implemented?
should i make them virtual and leave it to user to define them?
and for an implementation of class1 and and class2 say for example
 
class1<int,int,int,int,int> 

how can i check if the user is giving the setter of class2 the right typenames?

I really appreciate any comment or input on this :).
It depends on what you're doing. Do you have a reason for jumping thru these hoops?
Well i could not think of any other way. I am trying to abstract a routing framework with these classes so any user may define these classes based on his need.
class1 defines the state of the network one may define the state of the network based on number of active nodes while other define it as number of blocked links in the network. Based on this definition
class2 needs to make a routing decision.
Why is there 5 template args (and not 4 or 6 for example)?
this allows to define the state of the network with up to 4 variables, which in my case should be enough for defining a state (you can look at it sort of like a mapping function that
it takes 4 variables from the network and map it to a state.) but it its important to for the user to be able to implement this mapping passing any type of variable that suits his application
closed account (o1vk4iN6)
Wouldn't that be better accomplished with an abstract class ?
Thank you for your answer.
Is it possible to define the function but leave the argument types for the derived class to define?
Last edited on
> Is it possible to define the function but leave the argument types for the derived class to define?

I presume we are talking about functions that are run-time polymorphic.

In pure oops, a la Smalltalk, self and the like, yes.

In oops kludged over a static type system, a la C++, Java and the like, no.


Why do we need virtual functions at all for this? What we need is polymorphism across types. Wouldn't a compile-time mechanism suffice?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <tuple>
#include <string>
#include <iostream>

/*************  generic interface for map_state ****************************

template < typename STATE_TYPE, typename... VAR_TYPES > struct map_state
{
     STATE_TYPE operator() ( VAR_TYPES... variables ) const ;
     STATE_TYPE operator() ( const std::tuple< VAR_TYPES... >& variables ) const ;

     // TODO : announce types via typedefs
};

****************************************************************************/

struct map_my_state
{
     double operator() ( int a, int b, double c, double d, std::string str ) const
    { return a + b + c + d + str.size() ; }

     double operator() ( const std::tuple< int, int, double, double, std::string >& args ) const
    {
        return operator() ( std::get<0>(args), std::get<1>(args), std::get<2>(args),
                              std::get<3>(args), std::get<4>(args) ) ;
    }

    // TODO : announce types via typedefs
};

struct map_your_state
{
     std::string operator() ( std::size_t n, char c ) const
    { return std::string( n, c ) ; }

     std::string operator() ( const std::tuple< std::size_t, char >& args ) const
    { return operator() ( std::get<0>(args), std::get<1>(args) ) ; }

    // TODO : announce types via typedefs
};

template < typename MAPPER_TYPE, typename STATE_TYPE > struct router
{
    explicit constexpr router( const MAPPER_TYPE& state_mapper )
           : map_them(state_mapper) {}

    template < typename... VAR_TYPES  >
    void show_state( std::tuple< VAR_TYPES... >& data ) const
    { std::cout << map_them( data ) << '\n' ; }

    template < typename... VAR_TYPES  >
    void show_state( VAR_TYPES... variables ) const
    { std::cout << map_them( variables... ) << '\n' ; }

    const MAPPER_TYPE& mapper() const { return map_them ; }
    void mapper( const MAPPER_TYPE& new_mapper ) { map_them = new_mapper ; }

    // etc ...

    private:
        MAPPER_TYPE map_them ;
};

int main()
{
    map_my_state my_mapper ;
    router< map_my_state, double > my_router(my_mapper) ;
    my_router.show_state( 1, 2, 3.9, 4.8, "12345" ) ;
    std::tuple< int, int, double, double, std::string >
                        my_node_data( 14, 23, 1.05, 99.3, "abc" ) ;
    my_router.show_state( my_node_data ) ;

    map_your_state your_mapper ;
    router< map_your_state, std::string > your_router(your_mapper) ;
    your_router.show_state( 15, '@' ) ;
}
Thank you very much for your detailed reply.
I think this is what i was looking for and it serves my purpose well.
Just had a question:
Why do i need to announce the types via typedef ?? Because the router will get the state type as an argument anyway
> Why do i need to announce the types via typedef ??

It comes in handy, when we want to write a lot of polymorphic code involving the type.


> Because the router will get the state type as an argument anyway

If the result_type were announced, we would not need that second template parameter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
template < typename MAPPER_TYPE > struct router
{
    typedef typename MAPPER_TYPE::result_type state_type ;
    // ... as before
};

struct map_my_state
{
    typedef double result_type ;
    // ... as before
};

struct map_your_state
{
    typedef std::string result_type ;
    // ... as before
};


int main()
{
    map_my_state my_mapper ;
    router<map_my_state> my_router(my_mapper) ;
    // ... as before

    map_your_state your_mapper ;
    router<map_your_state> your_router(your_mapper) ;
    // ... as before
}

Topic archived. No new replies allowed.