Alternate implementation of “is_base_of” (checking base/derived relationship)
我正在研究如何在boost中实现is_base_of(这决定了在编译时给定的class是否是另一个class的基础)的问题。
第一次看到这样的代码,我惊讶于如何使事情如此完美地工作!但是,许多步骤让我感到困惑(在阅读所??有答案之后)。因此,我想知道是否可以替代地实现此功能。我尝试了以下操作:
1 2 3 4 5 6 7 8 9 10 11
| 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*始终具有不同的大小,并避免了典型的"是"和"否"的类型转换]
- 您可以使用dynamic_cast并检查空指针吗?
-
@wheaties:我对此表示怀疑,因为dynamic_cast是运行时的东西,这意味着它是编译时的工具。
-
代码中的一些注释呢?
-
@John Zwinck想了很多。需要在编译器的前面。
我认为链接解决方案中的关键部分是,无论最终结果是(相关的还是不相关的)-选择的转换顺序实际上都不会包含要测试的继承。选择check函数的适当版本时,编译器将其考虑在内。但是,最终每次选择的路径实际上都不会使用它。
但是在您的代码中,如果类是相关的,对check的调用确实的确利用了从Child*到B*的继承。而且-恐怕无法轻易解决,因为您介绍的方法非常不同。
如果相关
您的解决方案
Child是D,因此也是B。因此,存在从Child*到B*的转换。因此,check的第一个版本是可行的。 check的第二个版本以及Child也是dummy<int>都是可行的,因此Child*是dummy<int>*。选择第一个版本是因为它不涉及模板参数的专门化。
链接的解决方案
对于check的第一个版本:Host<B, D>通过用户定义的转换转换为D*。转换结果类型与function参数完全匹配。此处不使用继承。
对于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函数的一个版本具有模板参数的事实,那么路径将是无与伦比的。
如您所见,这两种方法明显不同。
- 很好的解释!甚至,我也对某些东西可以帮助解决该问题表示怀疑。我只是希望可能是我们可以package更多模板或利用const等。当用户想要省略private/protected继承时,可以使用此代码! :)