Boost logo

Boost :

From: John Maddock (John_Maddock_at_[hidden])
Date: 1999-11-27 08:17:47


Beman, Howard -

I've been messing with parameter_traits some more, using a variation of
Howards suggested modification for small types, it looks to work very well,
is very compact, and has the same semantics as the original (ie no extra
template parameters), however the following issues may need to be looked
at:

1) If type T is small, but expensive to copy (pimple deep copy) then the
implementation below will produce worse code than just using "const T&", if
necessary I can deal with this by using SGI style type_traits, to limit
specialisation to POD types. However that may exclude some types (small
iterators) that should be dealt with by the specialisation - take your pick
:-)

2) The array specialisation is somewhat shaky - I can find no good use for
it (although this could be a compiler problem) - I've also changed the
definition of decayed_type in this case to "T decayed_type[sz]" so that it
is actually different from the pointer version - in other words you can now
tell whether the pointer or array version was invoked by comparing the
compile time type of decayed_type with the passed template parameter (and
hence deduce that the parameter was decayed if they differ). Does anyone
have a concrete example where the array version is actually required?

Here is the example code:

#include <iostream>
#include <typeinfo>
#include <list>
#include <string>

using namespace std;

template <typename T, bool is_small>
struct parameter_traits_imp
{
   typedef const T& param_type;
   static const bool is_specialised = false;
};

template <typename T>
struct parameter_traits_imp<T, true>
{
   typedef T const param_type;
   static const bool is_specialised = true;
};

template<typename T>
struct parameter_traits
{
private:
   typedef parameter_traits_imp<T, bool(sizeof(T) <= sizeof(int))>
imp_type;
public:
   typedef typename imp_type::param_type parameter_type;
   static const bool is_specialised = imp_type::is_specialised;
   typedef T decayed_type;
};

template< typename T >
struct parameter_traits<T&>
{
   typedef T& parameter_type;
   static const bool is_specialised = true;
   typedef T& decayed_type;
};

template< typename T, int sz >
struct parameter_traits<T[sz]>
{
   typedef T decayed_type[sz]; // I think that this is wrong?
   typedef T* const parameter_type;
   static const bool is_specialised = true;
};

// usage example:

template< typename T >
struct single
{
    T value;
    single( typename parameter_traits<T>::parameter_type v ) :
value(v)
    {
        cout << "Constructing " << typeid(value).name()
             << " which contains " << value
             << " via ";
        if(parameter_traits<T>::is_specialised)
            cout << "specialisation";
        else
            cout << "non-specialisation";
        cout << endl;
    }
    virtual ~single(){}
};

template <class T>
void foo(T t, typename parameter_traits<T>::parameter_type v)
{
   cout << "calling foo<" << typeid(T).name()
       << "> which recieved " << v
             << " via ";
        if(parameter_traits<T>::is_specialised)
            cout << "specialisation";
        else
            cout << "non-specialisation";
        cout << endl;
}

struct big
{
   int a[5];
};

std::ostream& operator<<(ostream& os, const std::list<int>::iterator& li)
{
   os << (void*)(&li);
   return os;
}

std::ostream& operator<<(ostream& os, const big& b)
{
   os << (void*)(&b);
   return os;
}

big big_val;

int main()
{
    int i = 1;
    cout << "typeid(i).name() is " << typeid(i).name() << endl;
    single<int> x(i);
    single<int&> y(i);
    y.value = 2;
    single<const int&> cy(i);
// cy.value = 3; // error: assign to constant
    single<int*> z(&i);
    single<const int*> cz(&i);
// cz.value = 4; // error: assign to constant
    single<long> lx(i);
    char av[3] = { 'a', 'b', 0, };
    single<char*> a1(av);
    single<const char*> a2(av);
    single<const char*> a3("");
    single<char[3]> sa(av); // can't get this to work

    std::list<int> l;
    single<std::list<int>::iterator> sl(l.begin());
    std::string s;
    single<std::string> ss(s);

    single<big> sb(big_val);

    single<const int> ci(4);

    foo(i, i);
    foo(2, 2);
    foo(&i, &i);
    foo("", "");
    foo(s.begin(), s.end());
    foo(l.begin(), l.end());
    return 0;
}

- John.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk