3

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!

Navaneeth K N
  • 15,295
  • 38
  • 126
  • 184

2 Answers2

4

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
  • 12,749
  • 1
  • 27
  • 35
  • +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 Feb 21 '10 at 17:51
  • @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. – Navaneeth K N Feb 21 '10 at 17:54
  • @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 Feb 21 '10 at 18:00
  • @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. – Navaneeth K N Feb 21 '10 at 18:03
  • @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 Feb 21 '10 at 18:20
  • @Manuel: Let me try it. Thanks for your help. I really appreciate that. – Navaneeth K N Feb 21 '10 at 18:24
0
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
  • 256,549
  • 94
  • 388
  • 662