0

I want to do some static dispatch work, and let base class static_cast this pointer to derived class and call function of the same name to achieve polymorphism. I also want to use static_assert to make sure that derived class has indeed overloaded specific function (otherwise it will be endless loop). I tried to put static_assert at three places, but surprisingly find out that not all of them worked.

#include <iostream>

template<typename Type, Type Ptr>
struct MemberHelperClass;

#define DEFINE_HAS_MEMBER_FUNCTION(func) \
template<typename T, typename Type> \
static char MemberHelper_##func(MemberHelperClass<Type, &T::func>*); \
template<typename T, typename Type> \
static int MemberHelper_##func(...); \
template<typename T, typename Type> \
struct has_member_##func { \
    static constexpr bool value = sizeof(MemberHelper_##func<T, Type>(nullptr)) == sizeof(char); \
};

#define STATIC_ASSERT_HAS_MEMBER_FUNCTION(T_, F_, func) \
static_assert(has_member_##func<T_, F_>::value == 1, "function `"#func"` is undefined or inaccessible"); \

template<typename D>
class B
{
public:
    DEFINE_HAS_MEMBER_FUNCTION(f);

    // 1.??? why this assert always fail even if D::f is present
    // STATIC_ASSERT_HAS_MEMBER_FUNCTION(D, void(D::*)(), f);

    void f() {
        // 2.ok, assert fails only when B::f is called but D::f is not defined
        // STATIC_ASSERT_HAS_MEMBER_FUNCTION(D, void(D::*)(), f);

        static_cast<D*>(this)->f();
    }

protected:
    B() {
        // 3.ok, assert fails only when instance of D is declared but D::f is not defined
        // STATIC_ASSERT_HAS_MEMBER_FUNCTION(D, void(D::*)(), f);
    }
};

class D : public B<D>
{
public:
    // void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

template<typename T>
void g(B<T>* pB)
{
    pB->f();
}

int main()
{
    D d;
    g(&d);  // should print void D::f()
    return 0;
}

So why the first static_assert always fail? I thought it would be the best choice, as f is no need to be called. Moreover class D just needs to be declared, and no instance of D is required...

5
  • 1
    FYI, your post is missing line continuation on at least two important locations: the second and fourth lines of the macro. Just FYI. Commented Aug 2, 2018 at 16:45
  • ^That. You should learn about minimal reproducible example. In particular, the macro is just distracting. Commented Aug 2, 2018 at 16:46
  • Won't std::is_member_function_pointer work for you? Commented Aug 2, 2018 at 16:47
  • @WhozCraig oh sorry, I accidentally deleted them when formatting.... Commented Aug 2, 2018 at 17:08
  • @πάνταῥεῖ I tried that. But it seems that inherited member function B::f is also considered a member function of D so static_assert always pass... Commented Aug 2, 2018 at 17:11

1 Answer 1

1

At the time B<D>'s definition is implicitly instantiated, D is incomplete. Therefore, a static_assert inside B's class definition will not see anything in the definition of D. Member function bodies are only implicitly instantiated when used, at which point D is already complete.

class D : public B<D> // <--- B<D> implicitly instantiated here
{
public:
    // void f() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};  // <--- D becomes complete here
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.