downcasted pointer to member as template argument

I'm working in some code using the Curiously Recurring Template Pattern, where the derived class is passed up to specialize its own base classes at compile time.

With this, I run into an annoying problem which I have made a toy example for. I have annotated base::bar with comments describing the expected behavior (and why I expect it). The entire example is intended to be compiled as is, and results in 3 compiler errors (clang-3.9) as noted in the comments. For reference, $4.11/2:

A prvalue of type “pointer to member of B of type cv T”, where B is a class type, can be converted to a prvalue of type “pointer to member of D of type cv T”, where D is a derived class (Clause 10) of B. If B is an inaccessible (Clause 11), ambiguous (10.2), or virtual (10.1) base class of D, or a base class of a virtual base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to the member in D's instance of B. Since the result has type “pointer to member of D of type cv T”, it can be dereferenced with a D object. The result is the same as if the pointer to member of B were dereferenced with the B subobject of D. The null member pointer value is converted to the null member pointer value of the destination type.57

#include <type_traits>

template<typename impl_t>
struct super
{
        typedef int impl_t::* member_dat_t;

    protected:
        template<member_dat_t dat>
        int foo()
        {
                return static_cast<impl_t *>(this)->*dat;
        }
};

template<typename impl_t>
struct base : super<impl_t>
{
        using this_t = base<impl_t>;
        int base_dat = 0;

        int bar()
        {
                // This, of course, succeeds
                this-> template foo<&impl_t::derived_dat>();

                // This fails during template instantiation, because the compiler knows that the
                // location of base_dat/base_func is in the base<derived> subobject of a derived
                // object rather than derived itself.
                this-> template foo<&impl_t::base_dat>();
                // (i.e., this succeeds, despite the address being taken on a member resolved off the impl_t)
                static_assert(std::is_same<int this_t::*, decltype((&impl_t::base_dat))>::value, "");

                // But what if we cast, as the standard (N3242) permits in $4.11/2 [conv.mem]
                // Now, these succeed
                static_assert(std::is_same<int impl_t::*, decltype((static_cast<int impl_t::*>(&impl_t::base_dat)))>::value, "");
                static_assert(std::is_same<typename super<impl_t>::member_dat_t, decltype((static_cast<int impl_t::*>(&impl_t::base_dat)))>::value, "");
                // But these still fail
                this-> template foo<static_cast<int impl_t::*>(&impl_t::base_dat)>();
                this-> template foo<static_cast<typename super<impl_t>::member_dat_t>(&impl_t::base_dat)>();
                return 1;
        }
};

struct derived : base<derived>
{
        int derived_dat;
};

void test()
{
        derived d;
        d.bar();
}

For the "why": the existing code in base only ever instantiates super::foo with members actually defined in derived . It would please me if I could also use members defined in base<derived> , inherited by derived . The actual code is using member functions, but member data sufficed for the example.

Edit: I've technically come up with a solution that should work. Basically, base derives from super<base<impl_t>> instead of super<impl_t> , so now we can invoke foo with members of base<impl_t> , and if we need different behavior from the most-derived classes, we can make the methods in base virtual. But this throws away a little of the benefit of CRTP (we now have VTBL in the objects, and the cost of dynamic polymorphism, even when we know at compile time what we want).

Thanks

链接地址: http://www.djcxy.com/p/23334.html

上一篇: 访问派生类中的受保护成员

下一篇: 作为模板参数降级指向成员的指针