[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Explicit specialization of member template when type is another template type.

jason.cipriani@gmail.com

12/5/2008 5:26:00 AM

Here is a program, it looks weird but it models what I'm trying to do.
In this program:

- "Object" is just some example type.
- "Container" holds a single item of some type, but provides access
access to a copy of that object only via a nested class
Container::ContainedItem.

=== BEGIN ===

// An example object with a member function.
class Object {
public:
void function () const { }
};

template <typename T> class Container {
private:
T data_; // Container's instance of the data.
public:
// This just wraps an item.
class ContainedItem {
private:
T item_; // Some copy of the data.
public:
explicit ContainedItem (const T &item) : item_(item) { }
const T * getItem () const; // This gets the copy.
};
// Get via ContainedItem.
ContainedItem getData () const { return ContainedItem(data_); }
// Set value directly.
void setData (const T &data) { data_ = data; }
};

// Generic template implementation.
template <typename T>
const T * Container<T>::ContainedItem::getItem () const {
return &item_;
}

=== END ===


Now, my problem is very specific: When T is an arbitrary type I want
Container<T>::ContainedItem::getItem() to return a const T *, just
like it already does. However, when T specifically is a
boost::shared_ptr<X>, I want Container<T>::ContainedItem::getItem() to
return a const X *, not a const T *. For example:


=== BEGIN ===

#include <boost/shared_ptr.hpp>
using boost::shared_ptr;

int main () {
Container<Object> x;
Container<shared_ptr<Object> > y;
x.setData(Object()); // i want this
y.setData(shared_ptr<Object>()); // i want this
x.getData().getItem()->function(); // i want this
y.getData().getItem()->get()->function(); // don't want this!
//y.getData().getItem()->function(); // i want this instead!
}

=== END ===


Basically, as shown above, for shared_ptr<X> template types, I don't
want the extra "get()" in there (boost::shared_ptr<X> does not define
a conversion to X*). Is there some way I can make an explicit
specialization for getItem(), for type T = boost::shared_ptr<X>, and
have it return a const X * (it would return "item_.get()" instead of
"&item_")? I can't figure out the syntax for it, if it's possible.

Is there some other solution instead? It's not that I don't want to
type "get()", it's that I want Container<X> and
Container<shared_ptr<X> > to have getData().getItem() return the same
type for both.

Thanks,
Jason
5 Answers

jason.cipriani@gmail.com

12/5/2008 5:31:00 AM

0

On Dec 5, 12:25 am, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.com> wrote:
> Here is a program, it looks weird but it models what I'm trying to do.
> In this program:
>
>   - "Object" is just some example type.
>   - "Container" holds a single item of some type, but provides access
> access to a copy of that object only via a nested class
> Container::ContainedItem.
>
> === BEGIN ===
>
> // An example object with a member function.
> class Object {
> public:
>         void function () const { }
>
> };
>
> template <typename T> class Container {
> private:
>         T data_; // Container's instance of the data.
> public:
>         // This just wraps an item.
>         class ContainedItem {
>         private:
>                 T item_; // Some copy of the data.
>         public:
>                 explicit ContainedItem (const T &item) : item_(item) { }
>                 const T * getItem () const; // This gets the copy.
>         };
>         // Get via ContainedItem.
>         ContainedItem getData () const { return ContainedItem(data_); }
>         // Set value directly.
>         void setData (const T &data) { data_ = data; }
>
> };
>
> // Generic template implementation.
> template <typename T>
> const T * Container<T>::ContainedItem::getItem () const {
>         return &item_;
>
> }
>
> === END ===
>
> Now, my problem is very specific: When T is an arbitrary type I want
> Container<T>::ContainedItem::getItem() to return a const T *, just
> like it already does. However, when T specifically is a
> boost::shared_ptr<X>, I want Container<T>::ContainedItem::getItem() to
> return a const X *, not a const T *. For example:
>
> === BEGIN ===
>
> #include <boost/shared_ptr.hpp>
> using boost::shared_ptr;
>
> int main () {
>         Container<Object> x;
>         Container<shared_ptr<Object> > y;
>         x.setData(Object()); // i want this
>         y.setData(shared_ptr<Object>()); // i want this
>         x.getData().getItem()->function(); // i want this
>         y.getData().getItem()->get()->function(); // don't want this!
>         //y.getData().getItem()->function(); // i want this instead!
>
> }
>
> === END ===
>
> Basically, as shown above, for shared_ptr<X> template types, I don't
> want the extra "get()" in there (boost::shared_ptr<X> does not define
> a conversion to X*). Is there some way I can make an explicit
> specialization for getItem(), for type T = boost::shared_ptr<X>, and
> have it return a const X * (it would return "item_.get()" instead of
> "&item_")? I can't figure out the syntax for it, if it's possible.
>
> Is there some other solution instead? It's not that I don't want to
> type "get()", it's that I want Container<X> and
> Container<shared_ptr<X> > to have getData().getItem() return the same
> type for both.


I'm sorry, I mistitled this post. Originally I had been playing with
member templates and that's what I had on my mind when I typed the
subject. Should probably read "template member" I guess, or something.

Jason

Triple-DES

12/5/2008 7:29:00 AM

0

On 5 Des, 06:25, "jason.cipri...@gmail.com" <jason.cipri...@gmail.com>
wrote:

> === BEGIN ===
>
> // An example object with a member function.
> class Object {
> public:
>         void function () const { }
>
> };
>
> template <typename T> class Container {
> private:
>         T data_; // Container's instance of the data.
> public:
>         // This just wraps an item.
>         class ContainedItem {
>         private:
>                 T item_; // Some copy of the data.
>         public:
>                 explicit ContainedItem (const T &item) : item_(item) { }
>                 const T * getItem () const; // This gets the copy.
>         };
>         // Get via ContainedItem.
>         ContainedItem getData () const { return ContainedItem(data_); }
>         // Set value directly.
>         void setData (const T &data) { data_ = data; }
>
> };
>
> // Generic template implementation.
> template <typename T>
> const T * Container<T>::ContainedItem::getItem () const {
>         return &item_;
>
> }
>
> === END ===
>
> Now, my problem is very specific: When T is an arbitrary type I want
> Container<T>::ContainedItem::getItem() to return a const T *, just
> like it already does. However, when T specifically is a
> boost::shared_ptr<X>, I want Container<T>::ContainedItem::getItem() to
> return a const X *, not a const T *. For example:
>
> === BEGIN ===
>
> #include <boost/shared_ptr.hpp>
> using boost::shared_ptr;
>
> int main () {
>         Container<Object> x;
>         Container<shared_ptr<Object> > y;
>         x.setData(Object()); // i want this
>         y.setData(shared_ptr<Object>()); // i want this
>         x.getData().getItem()->function(); // i want this
>         y.getData().getItem()->get()->function(); // don't want this!
>         //y.getData().getItem()->function(); // i want this instead!
>
> }
>
> === END ===

Note that
template <typename T> const T * Container< shared_ptr<T>
>::ContainedItem::
getItem () const

is a partial specialization of the member function getItem, and you
cannot partially specialize member function of class templates. To
avoid having to specialize the entire class template, you could
perhaps do something like this:

template<typename T> struct ContainerTraits {
typedef const T * ReturnType;
static ReturnType get(const T& t) { return &t; }
};

template<typename T> struct ContainerTraits< shared_ptr<T> > {
typedef const T * ReturnType;
static ReturnType get(const shared_ptr<T>& p) { return p.get(); }
};

// declaration of getItem:
typename ContainerTraits<T>::ReturnType getItem () const;

// definition of getItem:
template <typename T> typename ContainerTraits< T >::ReturnType
Container<T>::ContainedItem::getItem () const {
return ContainerTraits<T>::get(item_);
}

int main() {
Container<Object>().getData().getItem()->function(); // ok
Container< shared_ptr<Object> >().getData().getItem()->function
(); // ok
}

jason.cipriani@gmail.com

12/5/2008 8:16:00 AM

0

On Dec 5, 2:28 am, Triple-DES <DenPlettf...@gmail.com> wrote:
> On 5 Des, 06:25, "jason.cipri...@gmail.com" <jason.cipri...@gmail.com>
> wrote:
>
>
>
> > === BEGIN ===
>
> > // An example object with a member function.
> > class Object {
> > public:
> >         void function () const { }
>
> > };
>
> > template <typename T> class Container {
> > private:
> >         T data_; // Container's instance of the data.
> > public:
> >         // This just wraps an item.
> >         class ContainedItem {
> >         private:
> >                 T item_; // Some copy of the data.
> >         public:
> >                 explicit ContainedItem (const T &item) : item_(item) { }
> >                 const T * getItem () const; // This gets the copy.
> >         };
> >         // Get via ContainedItem.
> >         ContainedItem getData () const { return ContainedItem(data_); }
> >         // Set value directly.
> >         void setData (const T &data) { data_ = data; }
>
> > };
>
> > // Generic template implementation.
> > template <typename T>
> > const T * Container<T>::ContainedItem::getItem () const {
> >         return &item_;
>
> > }
>
> > === END ===
>
> > Now, my problem is very specific: When T is an arbitrary type I want
> > Container<T>::ContainedItem::getItem() to return a const T *, just
> > like it already does. However, when T specifically is a
> > boost::shared_ptr<X>, I want Container<T>::ContainedItem::getItem() to
> > return a const X *, not a const T *. For example:
>
> > === BEGIN ===
>
> > #include <boost/shared_ptr.hpp>
> > using boost::shared_ptr;
>
> > int main () {
> >         Container<Object> x;
> >         Container<shared_ptr<Object> > y;
> >         x.setData(Object()); // i want this
> >         y.setData(shared_ptr<Object>()); // i want this
> >         x.getData().getItem()->function(); // i want this
> >         y.getData().getItem()->get()->function(); // don't want this!
> >         //y.getData().getItem()->function(); // i want this instead!
>
> > }
>
> > === END ===
>
> Note that
> template <typename T> const T * Container< shared_ptr<T>>::ContainedItem::
>
> getItem () const
>
> is a partial specialization of the member function getItem, and you
> cannot partially specialize member function of class templates. To
> avoid having to specialize the entire class template, you could
> perhaps do something like this:
>
> template<typename T> struct ContainerTraits {
>   typedef const T * ReturnType;
>    static ReturnType get(const T& t) { return &t; }
>
> };
>
> template<typename T> struct ContainerTraits< shared_ptr<T> > {
>   typedef const T * ReturnType;
>   static ReturnType get(const shared_ptr<T>& p)  { return p.get(); }
>
> };
>
> // declaration of getItem:
> typename ContainerTraits<T>::ReturnType getItem () const;
>
> // definition of getItem:
> template <typename T> typename ContainerTraits< T >::ReturnType
> Container<T>::ContainedItem::getItem () const {
>   return ContainerTraits<T>::get(item_);
>
> }
>
> int main() {
>   Container<Object>().getData().getItem()->function(); // ok
>   Container< shared_ptr<Object> >().getData().getItem()->function
> (); // ok
>
> }


Oh, I think I get it, that's pretty neat. So... the purpose of
ContainerTraits is to take anything you'd need to specialize out of a
member function that can't be partially specialized, and move it into
a class that can be? And also, I guess it can simplify more complex
templates by letting you use, say, ContainerTraits<T>::ReturnType
everywhere instead of having to make specializations all over the
place.

Thanks,
Jason

Triple-DES

12/5/2008 11:10:00 AM

0

On 5 Des, 09:16, "jason.cipri...@gmail.com" <jason.cipri...@gmail.com>
wrote:
> On Dec 5, 2:28 am, Triple-DES <DenPlettf...@gmail.com> wrote:

> Oh, I think I get it, that's pretty neat. So... the purpose of
> ContainerTraits is to take anything you'd need to specialize out of a
> member function that can't be partially specialized, and move it into
> a class that can be? And also, I guess it can simplify more complex
> templates by letting you use, say, ContainerTraits<T>::ReturnType
> everywhere instead of having to make specializations all over the
> place.
>

Yes, in fact I made the trait class just for the return type. Then I
realized that the logic for getting the T* had to be specialized as
well. I suppose the class template could be turned into a full-fledged
function object, since it is no longer a pure "traits" class
(according to some definitions of the term).

I think it is a fairly common approach to delegate to a function
object when you want something like partial specialization for a
function template (or a member function of a template). At least I
have done this myself occasionally.

jason.cipriani@gmail.com

12/5/2008 5:33:00 PM

0

On Dec 5, 6:09 am, Triple-DES <DenPlettf...@gmail.com> wrote:
> On 5 Des, 09:16, "jason.cipri...@gmail.com" <jason.cipri...@gmail.com>
> wrote:
>
> > On Dec 5, 2:28 am, Triple-DES <DenPlettf...@gmail.com> wrote:
> > Oh, I think I get it, that's pretty neat. So... the purpose of
> > ContainerTraits is to take anything you'd need to specialize out of a
> > member function that can't be partially specialized, and move it into
> > a class that can be? And also, I guess it can simplify more complex
> > templates by letting you use, say, ContainerTraits<T>::ReturnType
> > everywhere instead of having to make specializations all over the
> > place.
>
> Yes, in fact I made the trait class just for the return type. Then I
> realized that the logic for getting the T* had to be specialized as
> well. I suppose the class template could be turned into a full-fledged
> function object, since it is no longer a pure "traits" class
> (according to some definitions of the term).
>
> I think it is a fairly common approach to delegate to a function
> object when you want something like partial specialization for a
> function template (or a member function of a template). At least I
> have done this myself occasionally.

Cool, thanks for the help!

Jason