Class Concept

Introduction

The class_ concept is a very versatile tool for exposing classes to the scripting engine.

These are the data that the class_ concept needs to know about.

value_type The class you want to register
base_type The base class (optional) 
wrapped_type Described below (optional)
storage_policy Information about how to store the registered class (value_type) internally (optional)
storage_type A class representing value_type, but inheriting from value. (If value_type inherits from value, storage_type == value_type)

wrapped_type can be used in two similar ways:

  1. To allow a scripting class to represent a native type (double is the wrapped_type of class number)
  2. If value_type is a class that does not inherit from value, wrapped_type == value_type

This imposes the restriction that only classes inheriting from value can be used to wrap native types (such as double)

Example:

    //Define some integer class
    class my_int {
	my_int(int input);	
	operator int&() const;
	operator+...
    };

    //Expose the integer class, and let it represent int internally
    class_<my_int,int> cls(...); //Fails!

    //Expose the std::string class, and let it represent const char* internally
    class_<std::string,const char*> cls(...); //Fails!

This restriction will disappear in future versions of CliPP.

Usages

Let us examine the most common usages of the class_ concept.

Classes inheriting from value:

1. scripting class without (relevant) base classes

    class object : public value {
	...
    };

    //Simple class
    class_<object> cls(...); 
    //value_type   == object ( == storage_type)

2. scripting class with a base class

    class array : public object {
	...
    };

    //Make scripting functionality defined in the object class available to array
    class_<array,object> cls(...);
    //value_type   == array ( == storage_type)
    //base_type    == object

3. Scripting class with a base class, wrapping a native value

    class number : public object {
	number(const double&);
	operator double&();
	...
    };

    //Class with a base, representing a native 
    class_<number,object,double> cls(...);
    //value_type   == number ( == storage_type)
    //base_type    == object
    //wrapped_type == double

    ...
    context* c=...;
    double value=5.0;
    wrap(value,c); //Will create a new instance of the number class 

Classes NOT inheriting from value

1. class without (relevant) base classes. With a storage policy.

    namespace std {
       template<typename T> class complex;
    };
    //Class with a base, representing a native 
    class_<std::complex<double>,direct_storage_policy> cls(...);
    //value_type   == std::complex<double>
    //storage_type == wrapped_type<value_type>
    //wrapped_type == std::complex<double>
    //storage_policy == direct_storage_policy

    ...
    context* c=...;
    std::complex<double> value(5.0,1.0);
    wrap(value,c); //Will create a new instance of wrapped_type<std::complex<double> >

More on storage policies in the next chapter...