简体   繁体   中英

Is it possible to check if an abstract class is copy-constructible, ignoring abstractness?

Consider those classes:

struct A
{
    A(A &&) = default;
    A &operator=(A &&) = default;
    virtual void foo() = 0;
};

struct B
{
    virtual void bar() = 0;
};

Both A and B are not copy-constructible (and not constructible at all), but B would be copy-constructible if it wasn't abstract.

Is it possible to write a type trait to check if a class has a copy constructor, that works even on abstract classes?

std::is_copy_constructible can't be used here, because abstract classes are not constructible. std::is_copy_assignable is a reasonable approximation, but would fail for quirky classes that have a copy constructor but not a copy assignment, or the other way around.


Why I need it: I have a unique_ptr -like class that, among other things, uses type erasure to allow deep-copying. Deep-copying (both constructing and assigning) requires the stored type to have a copy constructor. Since you might also want to store non-copyable classes in it, the smart pointer currently stops being copyable if its template parameter is not copy-constructible... which inadvertently disables copying if the template parameter is an abstract class, even if it does have a copy constructor.

Deep copying of a dynamic type through a pointer to a base type (whether a unique_ptr is involved or not) should be invoked through a virtual member function that is accessible through the base type. You should not be trying to deep copy a dynamic type through a pointer to a base type with a copy constructor, so the presence or absence of a copy constructor should be irrelevant to your code.

In any case, any expression which would check for the presence of a copy constructor would by definition have to be constructing a value of that type. And if is abstract, then that can't happen; any such expression is already invalid on that base. There isn't really a way around that.


Deep-copying (both constructing and assigning) requires the stored type to have a copy constructor.

No, it doesn't. A type being deep copyable merely requires that the stored type have some mechanism to create a proper dynamic instance of itself, which may be of some other type. You are choosing to require the presence of a copy constructor.

The correct solution is to stop making choices that make your solution harder/impossible. The type being pointed to can be one of three cases:

  1. The user doesn't want to be able to copy this type.
  2. The user wants to be able to copy this type.
  3. The user wants to be able to copy any object of a dynamic type that (visibly) inherits from this type. Let us call this "cloning".

How you divine clonable from non-copyable and copyable is up to you, but it has to be something explicit which the creator of that type has made possible. You can't just assume the user's intent; they have to tell you in some way. And that determination needs to be in some way intrinsic to the type in question. If you want a user to be able to take a type they don't own and forces it to be clonable, then you can use a traits class to allow them to declare that intent from outside of the class itself.

Ultimately, it makes no sense for clonability to be a runtime property. It makes no sense for a type to sometimes be clonable and sometimes not. Even if the cloning operation itself comes through a function pointer that is given to the pointer (I have no idea why you'd want that, since how you clone a type shouldn't be different for different instances of the pointer that use the same type), the determination about whether the type uses normal copying or cloning should be an intrinsic and explicit property of the type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM