I'm building a non-templated weak pointer type, similar to boost::any in that it knows the type of the underlying value it points to, except it does not copy (it only takes the address). I realize that's not the safest thing in the world, but in the limited context I'm using it its fine.
Also, to make things less confusing I'll call my type "Reference" (capital R), and the C++ language version "reference" (like int&).
Anyway, I have two copy constructors for my Reference class: one accepts a const reference (to a Reference), while the other accepts a non-const reference. The reason being is the non-const copy constructor copies the mutability (held as a boolean) of the Reference, while the const copier copies it as an immutable Reference (which causing an error if you try to cast the Reference into a non-const reference). MSVC doesn't like that, and gives me the warning C4521 - "multiple copy constructors specified". Clang doesn't seem to mind though, which is interesting since MSVC has let me get away with more non-standard stuff than Clang in the past.
At the moment I'm considering abandoning the concept of Immutable References, because all it does is enforce const-correctness at runtime which is actually causing more issues than it solves (not only do you have to check the Type and Validity of the Reference, but you also need to check its mutability). I could do this by only allowing creation of References to non-const data, or by using a const_cast.
> Anyway, I have two copy constructors for my Reference class:
> one accepts a const reference (to a Reference), while the other accepts a non-const reference.
That is fine.
[Note: All forms of copy/move constructor may be declared for a class.
[Example:
1 2 3 4 5 6
struct X {
X(const X&);
X(X&); // OK
X(X&&);
X(const X&&); // OK, but possibly not sensible
};
—end example ]
—end note ] - IS
> What should I do?
Hard to say, without seeing what the class looks like.
I've included a portion of the class header. There's some stuff missing (the Unpack<T>(Reference) functions are not included), but you get the gist of it. I still can't figure out why exactly MSVC would throw a warning for this, as it seems like perfectly reasonable behavior to me.
Certain sets of names and function signatures are always reserved to the implementation:
— Each name that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.
— Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
Isn't this is a somewhat unusual (unintuitive) interpretation of const-ness?
1 2
/** Copy immutable reference from copy */
Reference(const Reference& copy);
That const Reference means not only that the object is const, but also that the object referred to by it is const.
1 2 3 4 5 6 7 8 9 10 11
int value = 0 ;
constint cvalue = 0 ;
int* p = std::addressof(value) ; // (non-cost) pointer to (non-cost) int // 1
constint* pc = std::addressof(value) ; // (non-cost) pointer to const int // 2
int* const cp = std::addressof(value) ; // const pointer to (non-cost) int // 3
constint* const cpc = std::addressof(value) ; // const pointer to const int // 4
Reference r(value) ; // (non-cost) Reference to (non-cost) int // 1
Reference rc(cvalue) ; // (non-cost) Reference to const int // 2
const Reference cr(value) ; // const Reference to (non-cost) int // 3
const Reference crc(cvalue) ; // const Reference to const int // 4
template <typename AnyType>
Reference( AnyType&& value ) = delete ;
Can't you ensure runtime const correctness by storing the type_info or type_index of the pointer?
Though, typeid(int) == typeid( constint ), typeid(int*) != typeid( constint* )
Thanks! After some thought I decided to ditch having a const Reference force its referenced value to be const as well (so now there's only one copy constructor), though it still won't let you unpack an immutable Reference into a non-const reference. I also got rid of the double underscores, didn't know that was an issue.