There are various containers in STL, And the STL algorithm allows us to perform various operations on the elements in the container. The following program should be easy for every contemporary c ++ programmer:
# Include <iostream>
# Include <list>
# Include <algorithm>
# Include <string>
Using namespace STD;
Struct print
{
Void operator () (const string & _ Str)
{
Cout <_ STR <Endl;
}
};
Int main ()
{
List <string> str_list;
Str_list.push_front ("hello ");
Str_list.push_front ("world ");
List <string> another_list;
Another_list.push_back ("hello ");
Another_list.push_back ("world ");
For_each (str_list.begin (), str_list.end (), print ());
For_each (another_list.begin (), another_list.end (), print ());
}
Running result:
World
Hello
Hello
World
Simple things often illustrate the profound truth. In this program, what are the essential problems we encounter? First, we have a container. Second, we can put things in the container. Finally, we can use an algorithm to apply an operation to every (or part) in the container) element. This is the essence of the above procedures.
Mpl can be regarded as the compiling version of STL, or the metaprogramming version. It also provides various containers, except that the object is not data, but type. Their constructor syntax is similar, or even, I think, more interesting:
# Include <string>
# Include <iostream>
# Include <boost/MPL/at. HPP>
# Include <boost/MPL/list. HPP>
# Include <boost/MPL/push_front.hpp>
Using namespace boost;
Int main ()
{
Typedef mpl: list <> type_list1;
Typedef mpl: push_front <type_list1, int >:: type type_list2;
Typedef mpl: push_front <type_list2, std: string >:: type type_list;
// Or this is better
Typedef mpl: list <int, std: string> another_list;
Std: cout <typeid (mpl: at_c <type_list, 0 >:: type). name () <std: endl;
Std: cout <typeid (mpl: at_c <type_list, 1 >:: type). name () <std: endl;
Std: cout <typeid (mpl: at_c <another_list, 0 >:: type). name () <std: endl;
Std: cout <typeid (mpl: at_c <another_list, 1 >:: type). name () <std: endl;
}
A little explanation. Mpl: list is the meta-programming version of std: list, while mpl: push_front does not need to be mentioned. Mpl: at_c is a metaprogramming algorithm. It serves as a runtime [] operator, that is, to obtain elements at a certain position in a container. In VC7.1, the execution result is
Class std: basic_string <char, struct std: char_traits <char>, class std: allocator <char>
Int
Int
Class std: basic_string <char, struct std: char_traits <char>, class std: allocator <char>
This is almost the same as the list action in the runtime.
Of course, mpl also has for_each, and we can also provide a metaprogramming functor for for_each. What is metaprogramming functor? The runtime functor is a struct that provides operator () overloading, And the metaprogramming functor is a struct that provides the operator () template:
# Include <string>
# Include <iostream>
# Include <boost/mpl/at. hpp>
# Include <boost/mpl/list. hpp>
# Include <boost/mpl/push_front.hpp>
# Include <boost/mpl/for_each.hpp>
Using namespace boost;
Struct print
{
Template <class T>
Void operator () (const T &)
{
Std: cout <typeid (T). name () <std: endl;
}
};
Int main ()
{
Typedef mpl: list <> type_list1;
Typedef mpl: push_front <type_list1, int >:: type type_list2;
Typedef mpl: push_front <type_list2, std: string >:: type type_list;
Typedef mpl: list <int, std: string> another_list;
MPL: for_each <type_list> (print ());
MPL: for_each <another_list> (print ());
}
The output is exactly the same as the above MPL: at_c program.
Of course, until now, these programs have only stayed on pure toy programs. Can you do something useful? Of course. Suppose we have such an inheritance system: the root is an abstract class product, which has some Derived classes, such as PC and printer. Their common methods serialno will return their own product serial numbers, the serial number is determined during the construction:
Class Product
{
Public:
Virtual STD: String serialno () const = 0;
};
Class PC: Public Product
{
Public:
PC (const STD: string & _ Sn)
: Sn _ (_ Sn)
{}
STD: String serialno () const
{
Return Sn _;
}
PRIVATE:
STD: String Sn _;
};
Class printer: Public Product
{
Public:
Printer (const STD: string & _ Sn)
: Sn _ (_ Sn)
{}
STD: String serialno () const
{
Return Sn _;
}
PRIVATE:
STD: String Sn _;
};
Put these types in the same list using MPL: List. Of course, we want an implementation similar to the factory mode so that we can create them freely. The following program uses MPL: for_each to create an instance for each type in the list. Of course, it can be extended to do something useful.
# Include <string>
# Include <sstream>
# Include <iostream>
# Include <algorithm>
# Include <list>
# Include <boost/shared_ptr.hpp>
# Include <boost/mpl/at. hpp>
# Include <boost/mpl/list. hpp>
# Include <boost/mpl/for_each.hpp>
Using namespace boost;
Class Product
{
Public:
Virtual std: string SerialNo () const = 0;
};
Class PC: public Product
{
Public:
PC (const std: string & _ sn)
: Sn _ (_ sn)
{}
Std: string SerialNo () const
{
Return sn _;
}
Private:
Std: string sn _;
};
Class Printer: public Product
{
Public:
Printer (const std: string & _ sn)
: Sn _ (_ sn)
{}
Std: string SerialNo () const
{
Return sn _;
}
Private:
Std: string sn _;
};
Struct print
{
Template <class T>
Void operator () (const T & product)
{
Std: cout <"Type:" <typeid (T). name ()
<"SerialNo:" <product. SerialNo () <std: endl;
}
};
// Because neither PC nor Print has the default constructor, you must add this
Template <class T>
Struct wrap {};
Struct Create
{
Create (const std: string & _ line)
: Line _ (_ line)
, Serial _ (0)
{}
Template <class T>
Void operator () (WRAP <t>)
{
STD: stringstream SS;
SS <line _ <'_' <serial _ ++;
Shared_ptr <t> product (New T (ss. STR ()));
Print () (* product );
}
STD: String line _;
Unsigned long serial _;
};
Int main ()
{
Typedef MPL: List <printer, Pc> product_list;
MPL: for_each <product_list, wrap <MPL: _ 1> (create ("line1 "));
}
Output:
Type: Class printer serialno: line00000
Type: Class PC serialno: line1_1