I want to ensure, that a derived class implements a specific static method. I think doing so should be possible using static_assert, std::is_same, decltype, CRTP and maybe making use of SFINAE. However, similar code I found so far is quite complex and it seems I do not yet fully understand it making me unable to adopt it to my needs.
What I tried so far is this
template <class T>
class Base
{
static_assert(std::is_same<decltype(T::foo(1)), int>::value, "ERROR STRING");
};
class Derived : public Base <Derived>
{
public:
static int foo(int i) { return 42; };
};
However, it does not compile telling me, that Derived does no have an element named foo even if the method is correctly implemented. Furthermore providing actual parameters for foo in the expression inside static_assert feels wrong.
Searching SO revealed a similar question which finally lead me to this piece of code where it is checked that a type has methods begin() and end() returning iterators. So I tried to adopt this code to my needs.
template <class T>
class Base
{
template<typename C>
static char(&g(typename std::enable_if<std::is_same<decltype(static_cast<int(C::*)(int)>(&C::foo)), int(C::*)(int)>::value, void>::type*))[1];
template<typename C>
static char(&g(...))[2];
static_assert(sizeof(g<T>(0)) == 1, "ERROR STRING");
};
But this code does not compile because the assertion fires.
So my questions are
typename C::const_iterator(C::*)() const
in the example code mean? Isn't it a const function returning C::const_iterator and taking no arguments? What exactly does C::*
mean? So why is int(C::*)(int)
then wrong in my case?I'am using MSVC 12 but if possible the code should be portable.
Hence the answer is 'No'. If a derived class defines a static method with the same signature as a static method in the base class, the method in the derived class is hidden by the method in the base class.
Static classes are sealed and therefore cannot be inherited. They cannot inherit from any class except Object. Static classes cannot contain an instance constructor.
Static methods are usually useful for operations that don't require any data from an instance of the class (from this ) and can perform their intended purpose solely using their arguments.
A static method in C# is a method that keeps only one copy of the method at the Type level, not the object level. That means, all instances of the class share the same copy of the method and its data. The last updated value of the method is shared among all objects of that Type.
This is a common problem when using CRTP: Base<Derived>
is instantiated at the point where it is encountered in Derived
's list of bases, at which time Derived
is not yet a complete type since the rest of its declaration hasn't been parsed yet. There are various workarounds. For static_assert
, you need to delay instantiation of the assertion until Derived
is complete. One way to do so is to put the assertion in a member function of Base
that you know must be instantiated - the destructor is always a good choice (Live at Coliru):
template <class T>
class Base
{
public:
~Base() {
static_assert(std::is_same<decltype(T::foo(1)), int>::value, "ERROR STRING");
}
};
class Derived : public Base<Derived>
{
public:
static int foo(int) { return 42; };
};
Addressing question #2: C::*
is the syntax for "pointer to member of class C
." So int(*)(int)
is "pointer to function taking a single int
parameter and returning int
", and int(C::*)(int)
is analogously "pointer to member function of C
taking a single int
parameter and returning int
." The monstrosity
typename C::const_iterator(C::*)() const
would translate to "pointer to constant member function of C
taking no parameters and returning C::const_iterator
" where of course the typename
is necessary to indicate that the dependent name C::const_iterator
is a type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With