Opened 9 years ago

Closed 8 years ago

#9201 closed Bugs (worksforme)

CopyConstructible, as a side effect, requires the type to be DefaultConstructible.

Reported by: David Laštovička <david@…> Owned by: jsiek
Milestone: To Be Determined Component: concept_check
Version: Boost Development Trunk Severity: Problem
Keywords: concept CopyConstructible DefaultConstructible Assignable Cc:

Description

The last line in the code bellow (i.e. 'TT b;') in fact requires the TT type to be DefaultConstructible. In my opinion that is not desired. I think that this bug is present also for other concepts (e.g. Assignable).

 BOOST_concept(CopyConstructible,(TT))
  {
    BOOST_CONCEPT_USAGE(CopyConstructible) {
      TT a(b);            // require copy constructor
      TT* ptr = &a;       // require address of operator
      const_constraints(a);
      ignore_unused_variable_warning(ptr);
    }
   private:
    void const_constraints(const TT& a) {
      TT c(a);            // require const copy constructor
      const TT* ptr = &a; // require const address of operator
      ignore_unused_variable_warning(c);
      ignore_unused_variable_warning(ptr);
    }
    TT b;
  };

Change History (9)

comment:1 by acharles, 9 years ago

I think the only way to fix this is to have the following approach:

  TT* b_ptr = NULL;
  if (b_ptr) {
    TT& b = *b_ptr;
    TT a(b); // Though I wonder if this shouldn't require an implicit copy constructor.
    TT* ptr = &a;
    ...
  }

This is the only way I can think of to create an object of type TT without relying on default construction, while also not invoking undefined behavior and also having it require compilation.

Is there a better idea?

Last edited 9 years ago by acharles (previous) (diff)

comment:2 by Jeremy W. Murphy <jeremy.william.murphy@…>, 8 years ago

It's an astute observation but I think it's a reasonable requirement and, given the requirements of CopyConstructible, not a bug. It requires that both

T(v)

and

T u = v;

be valid expressions. You can't assign to an object that is not already constructed.

comment:3 by david@…, 8 years ago

T u = v;

involves default construction and copy assignment, i.e. requires implementation of the default constructor

T()

and copy assignment operator

T &operator=(const T&)

Copy construction is implemented using copy constructor with signature

T(const T &)

My astute observation is: DefaultConstructible, CopyConstructible or CopyAssignable do correspond to the fact whether class implements default constructor, copy constructor or assignment operator.

As, on the level of the language, you can implement or not implement any of these 3 members independently on the presence of the implementation of the other 2, so I don't see a reason why there should be some dependencies on the level of the concepts.

It would be better to have a quotation from the standard rather than astute observations but my possibilities to quote do not go beyond sites like cppreference.com.

Personally I like to create classes that are always initialized with a constructor with arguments and I forbid the default constructor in order to avoid existence of uninitialized objects. That's how I bumped into this.

comment:4 by Steven Watanabe, 8 years ago

Did you actually test this bug or did you just get it by looking at the code? The implementation of BOOST_CONCEPT_ASSERT is smart enough to avoid requiring the default constructor. It uses a trick similar to acharles' comment. I tested it with both gcc and msvc and it seems to work.

T u = v; only requires the copy constructor. It does not do copy assignment.

comment:5 by david@…, 8 years ago

Yes, I did. And you did test it or are you just looking at the code? If you did, so maybe this issue can be closed. Note, that it was created 14 months ago, maybe it was addressed since then.

comment:6 by Steven Watanabe, 8 years ago

The code hasn't changed. I did test it, on more than one compiler.

#include <boost/concept_check.hpp>

struct no_default {
    no_default(const no_default&) {}
};

int main() {
    BOOST_CONCEPT_ASSERT((boost::CopyConstructible<no_default>));
}

Did you use BOOST_CONCEPT_ASSERT or something else?

It will definitely fail if you try any variation of:

CopyConstructible<T>();

but that's incorrect usage.

It's possible that there's a bug in one of the other interfaces. The problem could also be dependent on some other feature of TT or on a specific compiler version. If you can provide a test case that fails, I'll look into it, otherwise, I'll close the issue.

The compilers I used were VC 12 and gcc 4.8.3.

comment:6 by david@…, 8 years ago

Sorry for the previous post, you mentioned to test it...

Ok, I retested too, with boost 1.57 (gcc, linux), it is ok for me.

comment:7 by david@…, 8 years ago

Now I tested with BOOST_CONCEPT_ASSERT. I am not able to identify the code where it used to fail for me, so I can't exclude wrong usage (eh, I should have had put the usage into the issue text), but generally my code from that time is using BOOST_CONCEPT_ASSERT as well. Possibly I changed compiler since then (certainly: now I use native gcc 4.8.1, before I used windows crosscompiler, marked as experimental, let's blame that:) ). Anyway it seems ok now.

comment:8 by Steven Watanabe, 8 years ago

Resolution: worksforme
Status: newclosed
Note: See TracTickets for help on using tickets.