作为模板参数降级指向成员的指针
我正在使用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++