我正在讨论如何在boost中实现is_base_of(在编译时确定给定的class
是否是另一个class
的基础]。
第一次看到这样的代码,我惊讶于如何能够很好地工作!然而,我很难理解的许多步骤(在阅读完所有答案后)。所以,我想知道如果这个功能可以替代实现。我试过以下:
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*
将始终具有不同的大小,并避免使用典型的“是”和“否”进行类型转换。
答案 0 :(得分:2)
我认为链接解决方案的关键部分是无论最终结果是什么(相关或不相关) - 所选择的转换序列实际上不包括所测试的继承。编译器在选择适当版本的check
函数的过程中会考虑它。但是,每次最终选择的路径都不会实际使用它。
在您的代码中,如果类相关,则对check
的调用确实会使用从Child*
转换为B*
的继承。而且 - 我害怕无法轻易修复,因为你提出的方法是非常不同的。
如果相关
您的解决方案
Child
D
因此也是B
。因此,存在从Child*
到B*
的转换。所以Check
的第一个版本是可行的。 Check
的第二个版本是可行的,Child
也是dummy<int>
,因此Child*
是dummy<int>*
。选择第一个版本,因为这不涉及模板参数专业化。
关联解决方案
对于check
的第一个版本:Host<B, D>
通过用户定义的转换转换为D*
。转换结果类型与函数参数完全匹配。这里没有使用继承。
对于check
的第二个版本:Host<B, D>
会再次通过用户定义的转换转换为D*
。转换结果类型为D*
,可以进一步转换为B*
以匹配函数参数。这里确实使用了继承。
然而,最后编译器选择了第一个版本,因为它注意到转换结果更好地匹配check
的参数。
如果不相关
您的解决方案
Child
不是B
因此Check
的第一个版本不是选项。第二个版本是可行的,因为Child
仍然是dummy<int>
因此可以从dummy<T>
专门化。因为只有一个选项,所以选择是微不足道的。
关联解决方案
对于check
的第一个版本:Host<B, D>
通过用户定义的转化转换为D*
。
对于check
的第二个版本:Host<B, D>
已转换为const Host<B, D>
,然后通过用户定义的转化转换为B*
。
如果不是因为只有一个版本的check
函数具有模板参数,那么这些路径将是无法比拟的。
正如您所看到的,这两种方法有很大不同。