0

The test is as following:

class NotInit{};

NotInit NOT_INIT;

template<class T>
class Optional{

  T value;
  bool has_value;

public:
  Optional() : value(), has_value(false){}
  explicit Optional(NotInit):value(), has_value(false) {}
  explicit Optional(T const & val):value(val), has_value(true){}
  explicit Optional(Optional<T> const & other) {}

  Optional& operator=(Optional<T> const & other){}
  Optional& operator=(T const & other){}
};

enum X {
  FIRST
};

struct Some {
  Optional<X> member;
};

int main(int, char**){
  Optional<X> const opt(NOT_INIT);
  Some s = {NOT_INIT};
  return 0;
}

Clang 3.4 complains:

../st.cpp:31:12: error: no viable conversion from 'NotInit' to 'Optional<X>'
        Some s = {NOT_INIT};
                  ^~~~~~~~
1 error generated.

Why does it complain for the struct initialization but ont for the varaiable? Why is it not choosing the constructor with the proper parameter?

What overload is missing so that i can use this to init the struct?

I cannot use boost and i'm not sure this error would not appear if using boost::optional.

RedX
  • 14,749
  • 1
  • 53
  • 76
  • Why did you define your copy constructor as `explicit`? – Rerito Jan 26 '15 at 14:12
  • @Rerito that does not make any sense i'm sorry. I was just trying to build a working example. – RedX Jan 26 '15 at 14:19
  • You might find these useful: http://stackoverflow.com/questions/8283589/are-move-constructors-produced-automatically/8285499#8285499. I needed it to fully answer your question :) – Rerito Jan 26 '15 at 14:22

1 Answers1

1

You are marking your constructors explicit. Thus when you are trying to initialize your struct Some with a brace-initializer list, you are triggering an implicit conversion...

This is prevented here:

class NotInit;
template <typename T>
class Optional {
    // Here => Optional(NotInit) cannot be called implicitly
    explicit Optional(NotInit):value(), has_value(false) {}
};
/* ... */
Some s = {NOT_INIT}; // Implicit call to Optional<X>(NotInit): whoops!

If you remove the explicit, you can keep:

Some s = {NOT_INIT};

If you chose not to, then you'll have to instantiate s like this:

Some s = {Optional<X>(NOT_INIT)};

In any case, you'll have to remove the explicit keyword on your copy constructor (which has to perform a copy and not be a "dummy" constructor).
Why? Because once the Optional<X> object is built from NOT_INIT, a copy has to be made to s.member.

Note: You could also provide a move constructor, which would be more appropriate in that case, since the object you get from the conversion of NOT_INITis an rvalue.

Rerito
  • 5,886
  • 21
  • 47
  • @user2079303 Indeed it does. And not explicit ones. I guess you stated that because OP's copy constructor does nothing? – Rerito Jan 26 '15 at 13:32
  • whoops I was a bit confused, yes there is copy constructor in the question, but I couldn't get it to compile unless I made both `Optional(NotInit)` and the copy constructor non-explicit. – eerorika Jan 26 '15 at 13:43