作为模板参数降级指向成员的指针

我正在使用Curiously Recurring Template Pattern进行一些代码工作,其中派生类在编译时传递给它自己的基类。

有了这个,我遇到了一个令人讨厌的问题,我已经做出了一个玩具的例子。 我用注释描述了预期行为(以及为什么期望它)注释了base :: bar。 整个示例旨在按原样进行编译,并导致3个编译器错误(clang-3.9),如注释中所述。 作为参考,$ 4.11 / 2:

可以将“类型cv T的B的成员的指针”的类型值(其中B是类类型)转换为类型“指向c类型T的D的成员的指针”的值,其中D是派生类(如果B是D的不可访问(第11章),不明确(10.2)或虚拟(10.1)基类或D的虚拟基类的基类,则需要此转换的程序是病态的。 转换的结果与转换发生之前指向成员的指针指向相同的成员,但它指向基类成员,就好像它是派生类的成员一样。 结果指的是D的D实例中的成员。由于结果具有类型“指向C类型T的D成员的指针”,因此可以使用D对象解除引用。 结果与将B的成员指针与D的B子对象解引用的结果相同。空成员指针值被转换为目标类型的空成员指针值.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();
}

对于“为什么”: base的现有代码仅实例化了具有derived实际定义的成员的super::foo 。 如果我也可以使用base<derived>继承的成员定义的成员,它会让我derived 。 实际的代码使用成员函数,但成员数据已足够用于该示例。

编辑:我技术上想出了一个应该工作的解决方案。 基本上, base派生自super<base<impl_t>>而不是super<impl_t> ,所以现在我们可以使用base<impl_t>成员调用foo ,并且如果我们需要来自派生类最多的不同行为,那么我们可以使基础虚拟中的方法。 但是这会带来CRTP的一点好处(即使我们在编译时知道我们想要什么,我们现在在对象中也有VTBL,并且动态多态性的代价也是如此)。

谢谢

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

上一篇: downcasted pointer to member as template argument

下一篇: c++