“is_base_of”的替代实现(检查基/派生关系)
我正在解决一个很好的问题,关于如何在 boost 中实现 is_base_of (这决定了是否一个给定的类
在编译时是另一个类
的基础]
第一次看到这样的代码,我很惊讶事情如何能够如此顺利地工作!但是,我对许多步骤感到困惑(在阅读了所有答案之后),因此,我想知道是否可以替代地实现此功能:
template<class B, class D>
struct is_base_of
{
template<typename T> struct dummy {};
struct Child : D, dummy<int> {};
static B* Check (B*);
template<class T> static char Check (dummy<T>*);
static const bool value = (sizeof(Check((Child*)0)) == sizeof(B*));
};
按照一般情况的预期工作正常。
它 对于 private/protected
继承,它会选择预期的函数,但也会显示错误:- is an inaccessible base of ...
如果有人可以的话,我将不胜感激。建议对代码进行一些小的修改来解决这个问题(如果不是功能方面的,那么至少要消除错误消息)
[注意:我假设 char
和 B *
将始终具有不同的大小,并避免典型的“是”和“否”的类型转换]
I was going through a nice question for how is_base_of is implemented in boost (which decides if a given class
is a base of another class
at compile time].
Seeing such code for the 1st time, I got amazed that how things can be made to work so nicely! However, many steps I got confused to understand (after reading all the answers). So, I was wondering that if this functionality can be implemented alternatively. I tried following:
template<class B, class D>
struct is_base_of
{
template<typename T> struct dummy {};
struct Child : D, dummy<int> {};
static B* Check (B*);
template<class T> static char Check (dummy<T>*);
static const bool value = (sizeof(Check((Child*)0)) == sizeof(B*));
};
It works fine as per expectation for the general case.
The only problem is for private/protected
inheritance. It goes and choose the expected function, but also shows error as:- is an inaccessible base of ...
. I would appreciate if someone can suggest any little modification missing to the code to solve this problem (If not the functionality wise then at least to get rid of the error message).
[Note: I have assume that char
and B*
will always be of different sizes and avoided typecasting of typical 'yes' and 'no']
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为链接解决方案中的关键部分是,无论最终结果是什么(相关或不相关) - 所选的转换序列实际上不会包含所测试的继承。编译器在选择
check
函数的适当版本的过程中考虑了这一点。然而,每次最终选择的路径都不会实际使用它。但是,在您的代码中,如果类相关,则对
check
的调用确实会利用从Child*
转换为B*
的继承。这恐怕无法轻易解决,因为您提出的方法非常不同。如果相关
您的解决方案
Child
是D
因此也是B
。因此存在从Child*
到B*
的转换。因此Check
的第一个版本是可行的。Check
的第二个版本是可行的,Child
也是dummy
,因此Child*
是虚拟*
。选择第一个版本是因为它不涉及模板参数专门化。链接的解决方案
对于
check
的第一个版本:Host
通过用户定义的转换转换为D*< /代码>。转换结果类型与函数参数完全匹配。这里没有使用继承。
对于
check
的第二个版本:Host
通过用户定义的转换再次转换为D*
。转换结果类型为D*
,可以进一步转换为B*
以匹配函数参数。这里确实用到了继承。然而最终编译器选择了第一个版本,因为它注意到转换结果更好地匹配
check
的参数。如果不相关
您的解决方案
Child
不是B
,因此是Check
的第一个版本不是一个选择。第二个版本是可行的,因为Child
仍然是dummy
,因此可以从dummy
进行专门化。由于只有一种选择,因此选择是微不足道的。链接的解决方案
对于
check
的第一个版本:Host
通过以下方式转换为D*
用户定义的转换。对于
check
的第二个版本:Host
转换为const Host
,然后转换为B*
通过用户定义的转换。如果不是只有一个版本的
check
函数具有模板参数这一事实,这些路径将是无法比较的。正如您所看到的,这两种方法有显着不同。
I think the key part in the linked solution was that no matter what the end result would be (related or unrelated) - the chosen conversion sequence wouldn't actually include the inheritance that is tested for. Compiler is taking it into consideration in the process of selecting the appropriate version of the
check
function. However each time in the end the path selected wouldn't actually use it.In your code however if the classes are related, the call to
check
indeed does make use of the inheritence converting fromChild*
toB*
. And this - I'm afraid cannot be fixed easily as the approach that you presented is very different.If related
Your solution
Child
isD
therefore is alsoB
. Therefore there exists conversion fromChild*
toB*
. So the first version ofCheck
is viable. The second version ofCheck
is viable as well asChild
is alsodummy<int>
and thereforeChild*
isdummy<int>*
. The first version is selected as this doesn't involve template parameter specialization.The linked solution
For the first version of
check
:Host<B, D>
is converted via user defined conversion toD*
. The conversion result type exactly matches the function argument. No inheritance is used here.For the second version of
check
:Host<B, D>
is converted again via user defined conversion toD*
. The conversion result type isD*
which can be further converted toB*
in order to match the function argument. Inheritance is indeed used here.However in the end compiler chooses the first version as it was noted the conversion result better matches the argument of
check
.If unrelated
Your solution
Child
isn'tB
therefore the first version ofCheck
is not an option. Second version is viable as theChild
is stilldummy<int>
therefore can be specialized fromdummy<T>
. As there is only one option the choice is trivial.The linked solution
For the first version of
check
:Host<B, D>
is converted toD*
via user defined conversion.For the second version of
check
:Host<B, D>
is converted toconst Host<B, D>
and then toB*
via user defined conversion.The paths would be incomparable if it were not for the fact that only one version of
check
function has template arguments.As you can see the two approaches are significantly different.