I ask this question following the issue I raised here.
The point is quite simple. Suppose you have two classes of this kind:
template < class Derived >
class Base {
...
operator const Derived&() const {
return static_cast< const Derived& >(*this);
}
...
};
class Specialization : public Base<Specialization> {
...
};
Then suppose you have a type conversion like this one:
template < class T >
functionCall( const Base<T>& param) {
const T & val(param);
...
}
The question is: what should be the standard conforming behavior of this conversion?
Should it be the same as const T & val(static_cast<const T &> (param) ) or should it recursively iterate until stack overflow? Notice that I obtain the first behavior compiling with GNU g++ and the second compiling with Intel icpc.
I already tried to peek at the standard (section 5.9 on static_cast and section 12.3 on conversions) but due to my lack of experience I was not able to figure out the answer.
My many thanks in advance to anybody taking the time to help me out with this.
Looking at [expr.static.cast] in n3337 (first working draft after the Standard):
2/ An lvalue of type “cv1 B,” where B is a class type, can be cast to type “reference to cv2 D,” where D is a class derived (Clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists [...]
4/ Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t [..]
Therefore, I would interpret that gcc's behavior is the correct one, ie the expression:
static_cast<Derived const&>(*this)
should not invoke recursively operator Derived const& () const.
I deduce this from the presence of the Otherwise keyword which implies an ordering of the rules. The rule 2/ should be tried before the rule 4/.
The use of implicit conversion operators is not recommended. In C++11 you can add the keyword explicit not only to single argument constructors, but also to conversion operators. For C++03 code, you could use an explicitly named conversion function such as self() or down_cast().
Furthermore, you seem to be using the Base class for CRTP, i.e. to enable static polymorphism. That means that you have to know at compile-time which particular Derived class you are calling. Therefore, you should not have to use const Base& references in any public code, except to implement a CRTP interface.
In my projects, I have a class template enable_crtp:
#include <type_traits>
#include <boost/static_assert.hpp>
template
<
typename Derived
>
class enable_crtp
{
public:
const Derived& self() const
{
return down_cast(*this);
}
Derived& self()
{
return down_cast(*this);
}
protected:
// disable deletion of Derived* through Base*
// enable deletion of Base* through Derived*
~enable_crtp()
{
// no-op
}
private:
// typedefs
typedef enable_crtp Base;
// cast a Base& to a Derived& (i.e. "down" the class hierarchy)
const Derived& down_cast(const Base& other) const
{
BOOST_STATIC_ASSERT((std::is_base_of<Base, Derived>::value));
return static_cast<const Derived&>(other);
}
// cast a Base& to a Derived& (i.e. "down" the class hierarchy)
Derived& down_cast(Base& other)
{
// write the non-const version in terms of the const version
// Effective C++ 3rd ed., Item 3 (p. 24-25)
return const_cast<Derived&>(down_cast(static_cast<const Base&>(other)));
}
};
This class is privately derived from by any CRTP base class ISomeClass like this:
template<typename Impl>
class ISomeClass
:
private enable_crtp<Impl>
{
public:
// interface to be implemented by derived class Impl
void fun1() const
{
self().do_fun1();
}
void fun2()
{
self().do_fun2()
}
protected:
~ISomeClass()
{}
};
The various derived classes can implement this interface in their own specific way like this:
class SomeImpl
:
public ISomeClass<SomeImpl>
{
public:
// structors etc.
private:
// implementation of interface ISomeClass
friend class ISomeClass<SomeImpl>;
void do_fun1() const
{
// whatever
}
void do_fun2()
{
// whatever
}
// data representation
// ...
};
Outside code calling fun1 of class SomeImpl will get delegated to the appropriate const or non-const version of self() in the class enable_crtp and after down_casting the implementation do_fun1 will be called. With a decent compiler, all the indirections should be optimized away completely.
NOTE: the protected destructors of ISomeClass and enable_crtp make the code safe against users who try to delete SomeImpl* objects through base pointers.
Related
Why static_case conversion from base class to derived works inside base class, but doesn't work outside the base class
#include <iostream>
using std::cout;
class Base
{
public:
template <typename T>
int getValue() const { return static_cast<const T&>(*this).getValue(); }
};
class Derived: public Base
{
public:
Derived(int v): value(v) { }
int getValue() const { return value; }
int value;
};
class Another
{
int getValue() const { return 5; }
};
template <typename T>
void out(const Base & base) {
cout << base.getValue<T>() << '\n';
}
int main() {
Derived d(5);
Base b;
out<Derived>(d); //understandable, d has derived part.
out<Derived>(b); //don't understand, b is only base.
out<Another>(b); //compile time error
//static_cast<Derived>(b); //compile time error
}
I read this article about CRTP and stumble upon this code:
template <typename T>
class Base
{
public:
void doSomething()
{
T& derived = static_cast<T&>(*this);
use derived...
}
};
class Derived : public Base<Derived>
{
...
};
And I do not clearly understand how conversion works here too.
The static_cast conversion shall be used only if this conversion is legal. In your code you are creating an object of class Base, and you are trying to convert it to the class Derived. Luckily to you the implementation of the Derived::getValue() doesn't use any data members, and returns a value from literal. Anyway that is undefined behavior.
In case of CRTP no instance of Base class is created: only instances of the Derived are used.
Upd. Try this:
//static_cast<Derived>(b); doesn't compile
static_cast<Derived&>(b); shall compile
Upd 2. You get junk because the Derived::getValue() uses a data member (in your initial version of code data members were not used).
This is part of the rules of C++. static_cast can be used to convert a base class expression to derived class. If , at runtime, the object is not actually a base class subobject of a derived class object then it is undefined behaviour with no diagnostic required.
The first sentence of your question is incorrect, this cast can be written at any point of the code.
out<Another>() fails to compile because Another is not related by inheritance to Base.
Last cast in main() is incorrect syntactically and not equivalent to code in template, you can't upcast object to object (you can downcast through, causing type contraction). In templates above you cast references.
Derived& can be bound to Base&, static_cast have no way to check it. CRTP ensures it, because this point at storage of Derived type, *this results in reference that can be safely cast to Derived& reference object.
Reference to Another can't be bound to reference to Base, when Base is not base class of Another. In that case casting pointers or references using static_cast is illegal.
Template code is legal, in case of CRTP works because template code is instatiated where Derived is comlete enough type, i.e. where template was used. Template itself doesn't generate anything and isn't compiled, only checked for correctness.
Still, in CRTP some things won't be possible, e.g. to use inside of Base class nested type declarations from Derived class as complete types, for a simple reason : they are not complete and are not subject for forward lookup, unlike member variables and functions. If such use required, then a third type has to be defined before Base, contsining required declarations.
I'm reading item 28 on smart pointers of Scott Meyers's More Effective C++ and have the following question.
A complete demonstration can be found at http://ideone.com/aKq6C0 .
A derived class pointer can be converted implicitly to a base class pointer:
class Base {};
class Derived : public Base {};
void foo(Base* b) { cout << "foo called on Base pointer" << endl;}
Derived *d = new Derived();
foo(d); //No problem
But such implicit conversion cannot happen for smart pointers, i.e. SmartPtr<Derived> cannot be implicitly converted to SmartPtr<Base>. So we use a member template for such conversions:
template<typename T>
class SmartPtr {
public:
//constructors, operator->, etc
//member template for type conversion
template<NewType>
operator SmartPtr<NewType> () {
return SmartPtr<NewType>(pointee);
}
private:
T* pointee;//the raw pointer
};
This can almost work, but it can cause ambiguity:
class Remote {};
class Base : public Remote {};
class Derived : public Base {};
void foo(const SmartPtr<Remote>& p) { cout << "remote" << endl;}
void foo(const SmartPtr<Base>& p) { cout << "base" << endl;}
SmartPtr<Derived> d(new Derived());
foo(d);//compile error: ambiguity
In this example, the compiler does not know whether it should convert d to SmartPtr<Base> or SmartPtr<Remote>, although for a raw pointer Base is apparently superior. The book says
The best we can do is to use member templates to generate conversion functions, then use casts in those cases where ambiguity results.
But how exactly do we apply cast here? foo(static_cast<SmartPtr<Base>>(d)) does not compile either. From the error message I can tell that the error comes from the use of non-const reference in the copy-constructor of SmartPtr. I'm wondering what's the correct way to make the function call.
//constructors
This is the most important part that you have omitted :)
Your cast is correct as such, it all depends on set of constructors you have. If you have one that takes non-const ref - you would get the error you mentioned, if you can just change ref to being const in copy ctor and code would compile.
It may be not very obvious, but when you call
return SmartPtr<NewType>(pointee);
you are constructing new SmartPtr<NewType> that have to accept T*, and NewType and T are different types. Most likely you only have ctor that accepts raw pointer of same type (i.e. T* for SmartPtr<T> and X* for SmartPtr<X>) so compiler is looking for another converting ctor to create your new SmartPtr and finds your copy ctor, but it can't bind new value to non const ref
Edit:
IF you are using c++11 adding move ctor would also solve your problem as it would be able to bind to rvalue
SmartPtr( SmartPtr<T>&& other): pointee(other.pointee) { other.pointee = nullptr; }
Suppose I have a polymorphic hierarchy of classes with a common base:
struct Base { ~virtual Base() = default; };
I have inherited a large codebase which contains a long series of accessor functions (one for each derived type) that obtain a derived pointer via reinterpret_cast:
Derived * Get() // Derived inherits from Base
{
Base * b = lookup_derived();
return reinterpret_cast<Derived *>(b);
}
Obviously the code should be using static_cast or dynamic_cast (depending on whether the base is virtual). However, because this translation unit is large and the definitions of all the derived classes are jointly huge, the TU does not contain the definition of Derived, but only its declaration.
I would like to make this code more robust by adding to each derived class definition a static assertion that this reinterpret cast will produce the correct result. Essentially, I want something like this:
struct Derived : Base
{
static_assert(static_cast<Derived *>(std::declval<Base *>()) ==
reinterpret_cast<Derived *>(std::declval<Base *>()));
// ...
};
This constructions does not work of course since declval must not be evaluated, and the result of a reinterpret cast is not a constant expression. Is there any standard C++ mechanism to perform such a test statically? (The alternative would be a runtime check on this in the class constructor.)
Edit: Based on Aaron's post, I struck me that the question could be phrased entirely without reinterpret_casts:
static_cast<void *>(std::declval<Derived *>()) ==
static_cast<void *>(static_cast<Base *>(std::declval<Derived *>()))
I'm not sure if this will be good enough for the setup you have, but this code on ideone works for me (clang 3.5.0 and g++ 4.9.3).
Updated to cast in the other direction, i,e. Derived*-to-Base*, to more closely match the question. And also updated to use static_cast<void*> explicitly instead of C-style casting and reinterpret_cast .
template<typename D, typename B>
struct CheckCasting {
static D d_static;
constexpr
static B* bp = &d_static; // the original object is D,
// that allows us to static_cast both ways
static
constexpr bool static_equals_reinterpret() {
return static_cast<void*>(static_cast<D*>(bp))
== static_cast<void*>( bp );
}
};
struct Base {
constexpr Base() : i(0) {}
int i;
};
struct derived_with_virtual : public Base {
derived_with_virtual() {}
virtual void foo() { }
};
struct without_virtual : public Base {
without_virtual() {}
};
static_assert( ! CheckCasting<derived_with_virtual, Base> :: static_equals_reinterpret() ,"");
static_assert( CheckCasting<without_virtual , Base> :: static_equals_reinterpret() ,"");
A few comments:
I tried to replace the cast to void* with reinterpret_cast, but clang didn't like that. "note: reinterpret_cast is not allowed in a constant expression".
I tried moving the static_assert inside the Derived class without success.
This requires statically allocating an object for each Derived class.
It is easier to explain on an example so,
class base {
//....
}
class derived1 : public base {
//...
}
In my library, there is a pointer of base class. The user of the library have to make classes derived from either base or derived1 and assign pointer to that class.
How can I check what class is user-defined class derived from?
I have some remarks on the proposed compile-time x runtime solutions. In addition to when they are evaluated, is_base_of and dynamic_cast have different requirements and their answers can be different.
(1) First of all (as pointed out by others) to use dynamic_cast, base and derived classes must be polymorphic (must have at least one virtual method). is_base_of doesn't require the types to be polymorphic.
(2) The operands of is_base_of are both types whereas dynamic_cast needs a type (inside < >) and an object (inside ( )).
(3) dynamic_cast and is_base_of can give different answers (or one can compile while the other doesn't) depending on the type of inheritance (public vs protected or private). For instance consider:
struct B { virtual ~B() {} }; // polymorphic, so it can be used in a dynamic_cast
struct D1 : public B {}; // polymorphic by (public) inheritance
struct D2 : private B {}; // polymorphic by (private) inheritance
D1 d1;
D2 d2;
We have
static_assert(std::is_base_of<B, D1>::value, "");
static_assert(std::is_base_of<B, D2>::value, "");
assert(dynamic_cast<B*>(&d1));
assert(!dynamic_cast<B*>(&d2)); // Notice the negation.
Actually the last line yields a compiler error in GCC (error: 'B' is an inaccessible base of 'D2'). VS2010 does compile it (yielding just a warning similar to GCC's error message).
(4) The requirements on the classes being polymorphic can be relaxed through an exception handling trick. Consider:
struct B { }; // not polymorphic
struct D1 : public B {}; // not polymorphic
struct D2 : private B {}; // not polymorphic
D1 d1;
D2 d2;
template <typename B, typename D>
const B* is_unambiguous_public_base_of(const D* obj) {
try {
throw obj;
}
catch (const B* pb) {
return pb;
}
catch (...) {
}
return nullptr;
}
Then we have
static_assert(std::is_base_of<B, D1>::value, "");
static_assert(std::is_base_of<B, D2>::value, "");
assert((is_unambiguous_public_base_of<B>(&d1)));
assert(!(is_unambiguous_public_base_of<B>(&d2))); // Notice the negation.
It's worth mentionning that is_unambiguous_public_base_of is far slower than dynamic_cast and (this became more obvious after the renaming mentioned in the update below) always returns a nullptr for downcasts:
B* b1 = &d1;
assert(dynamic_cast<D1*>(b1)); // Requires D1 and B to be polymorphic.
assert(!(is_unambiguous_public_base_of<D1>(b1))); // Notice the negation.
A bit outdated reference on this trick is available in the following links:
Part 1, Part 2 and code
Disclaimer: the implementation of is_unambiguous_public_base_of above is just a draft to make the point and it doesn't handle const and volatile qualifications properly.
Update: In a previous version of this post is_unambiguous_public_base_of was named my_dynamic_cast and this was a source of confusion. So I renamed it to a more meaningful name. (Thanks to Jan Herrmann.)
You could use dynamic_cast.
if (dynamic_cast<DerivedClass*>(ptr)) {
std::cout << "Class is derived from DerivedClass.";
}
Check if class is derived from a specific class (compile time)
You can use std::is_base_of:
#include <type_traits>
....
const bool isBase = std::is_base_of<base, TheOtherClass>::value;
isBase is true if TheOtherClass is derived from base.
I think the answer to this question is very difficult. Of course there is std::is_base_of and dynamic_cast. Both provide you with some very limited information. The third option is function overloading. With all of those techniques you can choose a special path in your code which should be executed.
std::is_base_of can be interpreted in a boolean context and it is derived from either std::true_type or std::false_type. This fact makes it possible to use it as paramter for a function and use compile time polymorphism via function overloading. This first example shows how to use it in a boolean context, but you don't have any further specific type information. So compilation will fail in most circumstances (see here for a further description):
template<class T>
void do_it1(T const& t) {
if (std::is_base_of<T,derived1>::value) {
// we have a derived1
} else {
// we have a base
}
}
The second version is simple function overloading. Here compile time polymorphism is used but all runtime type information is lost (except virtual functions and dynamic_cast are used):
void do_it2(Base const& b) {
// we have a base your algorithm for base here
}
void do_it2(Derived2 const& d) {
// Derived algorithm here
}
Now the third version combines both:
template<class T>
void do_it3_impl(T const& t, std::true_type) {
// here t will be of a type derived from derived1
}
template<class T>
void do_it3_impl(T const& t,std::false_type) {
// here t will be of type not derived from derived1
}
template<class T>
void do_it_3(T const& t) {
do_it3_impl(t, std::is_base_of<T,derived1>()); // here we forward to our impl
}
The third variant is normaly used for header only libraries which don't use runtime poylmorphism (search for std::advance for an excample).
Now to runtime polymorphism. Here you have the dynaminc_cast variant:
void do_it4(Base const* ptr)
if (derived1 const* obj = dynamic_cast<derived*>(ptr)) {
// here we have obj with type derived1*
} else {
// here we have only base
}
If this variant is not fast enough you can implement your onw cast to derived1:
class derived1;
class base {
// as above
public:
virtual derived1 const* to_derived1() const {
return 0;
}
};
class derived1
: public base
{
// ...
virtual derived1 const* to_derived1() const {
return this;
}
};
void do_it5(Base const* ptr)
if (derived1 const* obj = ptr->to_derived1() {
// here we have obj with type derived1*
} else {
// here we have only base
}
This is fast but it scales very well for only very few (approximately 1) derived classes.
Last but not least you should think about your class design and deside what methods to make virtual and implement in base, derived1 or other classes. You should definitly look for strategy pattern.
You can do this in several ways. The most common ones as the others have pointed out are dynamic_cast<> and std::is_base_of. The latter is used at compile time, while dynamic_cast<> can be used at runtime.
HOWEVER, dynamic_cast<> will only work if your source class is polymorphic (i.e. has at least one virtual function - it can be a method or its destructor). If not, the compiler will trigger an error.
The compiler will only accept pointers to classes derived from your base class if your library functions takes pointers to the base class. My answer is with a classical approach type safety will handle it. To my experience that kind of type checking is enough. Having 25 years experience in the industry I question the need to do this check. Maybe such a fundamental question is not welcome? I would like to see the justification to having the need to do this kind of upcast. I never have to do that. The opposite, i.e. a down cast I need quite frequently.
My problem is this, I have a base class from which classes are derived. I have an overloaded += operator in the base class but I only want to be able to add derived classes of the same type. I do this by returning the lhs and producing a warning message if they are not the same type.
class base{
int variable;
public:
base(int v);
base & operator+=(const base & rhs);
class a: public base{
}
class b: public base{
}
base & operator+=(const base & rhs){
if(type_same(const & rhs){
variable+=rhs.variable; }
return *this
}
a first(1);
a second(5);
b third(2);
first+=second // first.variable now =6
second+=third // warning produced second.variable still = 5
I've never used dynamic cast before so my question is is it possible/advisable to a check using it and typeid to find out whether the types passed are the same. My alternative is a string constant name for each derived class.
Why have the operator+ in the base class in the first place? If you just place operator+ with the correct type into the a and b class, it will work, without any dynamic_cast.
dynamic_cast is usually a hint that your types are not well designed and should be avoided. In the described scenario, you can surely get by without any dynamic_cast. If not, then a and b should not be derived from base, as they do behave differently. Think about it from the user perspective: By deriving a from base, you tell the user that a can be used as base. If a method requires the actual type, move it down instead of putting it into the base interface.
The correct usage btw. would be to dynamic_cast the rhs to the current type (i.e. dynamic_cast<b*>(&rhs)) and if that returns a non-zero value, then rhs was indeed of the correct type (however, think about what happens if there is a class derived from b being passed in!)
To solve the problem that you stated in your post, dynamic_cast and RTTI are definitely the right tools. However, issuing a warning at runtime while providing compile-time support for a '+' operation may point to issues in the design where the users of your API would not expect exactly the behavior that your API provides.
My take: you could employ CRTP
The below code will issue the type mismatch error at compile time, as suggested by others.
template <typename Derived>
class base{
int variable;
public:
base(int v) { variable = v; }
Derived& operator+=(const Derived& rhs);
};
struct a: base<a> {
a(int v): base<a>(v) {}
};
struct b: base<b> {
b(int v): base<b>(v) {}
};
template <typename Derived>
Derived& base<Derived>::operator+=(const Derived& rhs)
{
variable += rhs.variable;
return static_cast<Derived&>(*this);
}
int main(int argc, const char *argv[])
{
a a1(1), a2(2);
b b1(1), b2(2);
a1 += a2;
b1 += a2; // compile time error :)
return 0;
}
Even if you really wanted to type the operator arguments as base& you'd at least gain the benefit of using static_cast<> because the conversion is exact and well defined at runtime. I can expand the idea in a few