Explicit specialization of member template when type is anothertemplate type.

J

jason.cipriani

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
 
J

jason.cipriani

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
 
T

Triple-DES

=== 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 said:
::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
}
 
J

jason.cipriani

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
 
T

Triple-DES

On Dec 5, 2:28 am, Triple-DES <[email protected]> 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.
 
J

jason.cipriani

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top