views:

690

answers:

2

I have a container class which uses boost::optional to hold the value. Here is the code looks like,

template<typename T>
struct traits
{
    typedef T  value_type;
    typedef T& reference;
};

template<typename T>
struct traits<const T>
{
    typedef const T  value_type;
    typedef const T& reference;
};

template<typename T>
struct traits<T*>
{
    typedef T* value_type;
    typedef T* reference;
};

template<typename T>
struct traits<const T*>
{
    typedef const T* value_type;
    typedef const T* reference;
};

template<typename T>
class container
{
public:

    typedef typename traits<T>::reference reference;
    typedef typename traits<T>::value_type value_type;

    container() {}

    void set(reference value) {
        op.reset(value);
    }

    reference get() const {
        return boost::get(op);
    }

private:
    boost::optional<value_type> op;
};

int main()
{
    foo f;
    container<const foo> c;
    c.set(f);
    return 0;
}

It works well for other types except const. I am getting error when I use const types (const foo* works fine).

  1. Is boost::optional supports constant types? If no, how can I work around this issue?
  2. Is there a ready made traits implementation available which I can use rather than defining my own traits?

Any help would be great!

+4  A: 

The problem is not with boost::optional, but with the logic of what you're trying to do. First you create a container of const, and then you try to modify what's contained. I would be surprised if that worked.

I think you should probably do what standard containers (like vector) do and forbid non-copyable template arguments.

Otherwise you'll have to live with the fact that your set method won't work when T is non-copyable, and provide a constructor that performs the initialization:

class container
{
public:

    container(reference init_value) : op(init_value) {}

};

int main()
{
    foo f;
    container<const foo> c(f);  // OK
    //   c.set(f);  NO
    return 0;
}
Manuel
+1 Well i agree with your criticism on his code. I deleted my answer because i found i'm teaching dangerous practice in it. If the purpose of the container is what we both suspect, then i agree with your answer.
Johannes Schaub - litb
@Manuel: I am not really experimenting to add different levels of indirection. I got lost in the templates world. I have a tree_node which holds a value as a key. Value will be stored in `optional`. Whenever I try the node with a different type, it is giving errors and can't make it work for all types.
Appu
@Appu - what you're doing is tricky, it's normal that you get into trouble if you don't have a lot of experience with C++. I'm curious, what makes you think you need to use `optional`?
Manuel
@Manuel: Please take a look at my other question. http://stackoverflow.com/questions/2274817/holding-a-generic-types-instance-c . I have explained why I started using optional.
Appu
@Appu - Sounds like a reasonable application of `boost::optional`. My advice is that you forget about all this traits madness, if the user wants to store pointers then the `reference` type should be a reference to a pointer, there's nothing wrong with that. That's the way STL containers work, by the way
Manuel
@Manuel: Let me try it. Thanks for your help. I really appreciate that.
Appu
A: 
template<typename T>
struct traits
{
    typedef T  value_type;
    typedef T& reference;
};

template<typename T>
struct traits<const T>
{
    typedef const T  value_type;
    typedef const T& reference;
};

Isn't the const specialization completely pointless? Without the specialization, traits<const int> will have const int as the value_type and const int& as the reference, which is exactly what you tried to achieve with the const specialization, right?

FredOverflow