This question has been updated. Please review the code.
The following code was compiled with VC++ Nov 2012 CTP. Scott Meyers' book "Effective C++" recommend that we should use the method of to avoid duplication in const and non-const member functions. However, the following code cause a warning (level 1). Because WDK build tool treats warnings as errors, so the following code cannot be compiled successfully.
Is there other better method?
struct A
{
int n;
A(int n)
: n(n)
{}
int Get() const
{
return n;
}
int Get()
{
return static_cast<const decltype(*this)&>(*this).Get();
}
};
int main()
{
const A a(8);
//
// warning C4717: 'A::Get' : recursive on all control paths,
// function will cause runtime stack overflow
//
a.Get();
}
You've transposed the bodies of the two Get
methods, so the compiler is correct; the const Get
method is calling itself. Aren't you glad now that your build tool treats warnings as errors? :)
Swap them round:
int& Get()
{
return const_cast<int&>(static_cast<const A&>(*this).Get());
}
const int& Get() const
{
return n;
}
I believed you got it reverse. This is the non-const version which casts away constness on the const version.
See: Elegant solution to duplicate, const and non-const, getters?
Answering the updated question.
(You should have made this a new question)
In static_cast<const decltype(*this)&>(*this)
, *this
is an lvalue of type A
, so the type denoted by decltype(*this)
is A&
(see 7.1.6.2 [dcl.type.simple]/4).
As a result your non-const Get()
function is equivalent to:
int Get()
{
typedef A & Aref;
// IMHO a const_cast would be the better choice here
return static_cast<const Aref&>(*this).Get();
}
cv-qualifiers on a reference type are ignored. With reference-collapsing, your cast is ultimately equvalent to static_cast<A&>(*this)
, so you don't add the const you need.
So using decl_type
does not work here. If you very badly want to use it, you'd need:
int Get()
{
// Made my suggested change of cast here
return const_cast<const std::remove_reference<decltype(*this)>::type&>(*this).Get();
}