【问题标题】:How can I detect whether a type is a visible base of another type?如何检测一种类型是否是另一种类型的可见基础?
【发布时间】:2012-04-11 07:44:04
【问题描述】:

如果我这样做

struct A{};
struct C:private A{};

typedef char (&yes)[1];
typedef char (&no)[2];

template <typename B, typename D>
struct Host
{
 operator B*() const;
 operator D*();
};

template <typename B, typename D>
struct is_base_of
{
template <typename T> 
static yes check(D*, T);
static no check(B*, int);

static const bool value = sizeof(check(Host<B,D>(), int())) == sizeof(yes);
};

int main(){
 std::cout<<is_base_of<A,C>::value<<std::endl;
}

我得到一个 1。我想在 C 是私有 A 时得到一个 0,当 C 是一个公共 A 时得到一个 1。

[代码来源于How does `is_base_of` work?]

【问题讨论】:

  • 有点跑题了,但如果你的声望低于 X,你真的能提供 X 的赏金吗?
  • 我删除了我的回答,基本上说“你不能”使用模板,以及可以做到这一点的模板替代方案。

标签: c++ templates inheritance


【解决方案1】:

您是否可以使用支持 C++11 的编译器?

如果是这样,您可以将 Chad 对static_cast 的使用与decltype 结合起来创建一个非常简单的类型特征实现(如this question 所示)。根据 Jonathan Wakely 的建议,当 D 定义 operator B&amp;() 时,引用已替换为指针以避免误报。

template<typename> struct AnyReturn { typedef void type; };

template<typename B, typename D, typename Sfinae = void>
struct is_base_of: std::false_type {};

template<typename B, typename D>
struct is_base_of<B, D,
    typename AnyReturn< decltype( static_cast<B*>( std::declval<D*>() ) ) >::type
>: std::true_type {};

使用 gcc 4.7 时:

struct Base {};
struct PublicDerived  : public  Base {};
struct PrivateDerived : private Base {};

int main()
{
    std::cout << is_base_of<Base, PublicDerived >::value << std::endl; // prints 1
    std::cout << is_base_of<Base, PrivateDerived>::value << std::endl; // prints 0
    return 0;
}

【讨论】:

  • 很好的答案,但如果B 具有operator A&amp;() 即转换为Ais_base_of&lt;A,B&gt; 会给出错误的结果。这可以通过将其更改为转换指针来解决,即static_cast&lt;B*&gt;( std::declval&lt;D*&gt;() )
  • 这也适用于 gcc 4.6.3,但 gcc 4.5.1 无法为PrivateDerived 编译:error: 'Base' is an inaccessible base of 'PrivateDerived'。我试图让这个(或它的任何变体)在 VS 2010 中工作的运气为零。它似乎无法处理模板中 decltypestatic_cast 的组合,可能会产生错误的结果甚至崩溃编译器。我将无法检查 VS 2011,因为它不支持 XP。
  • 假设此答案中的行为基于DR339,这在GCC 4.4 and laterClang 2.9 and later 中受支持,但在VC10 or VC11 中不支持。但是,访问检查并不要求是替换过程的一部分,这就是使用 GCC 4.5.1 时它会失败的原因。
【解决方案2】:

您是否需要可以在运行时评估的东西,还是一个简单的编译时错误就足够了?

struct A {};
struct B : private A {};

int main()
{
   B b;

   // gives error C2243: 'static_cast' : conversion from 'B *' to 'A &' exists, but is inaccessible
   A& a = static_cast<A&>(b);

   return 0;
}

【讨论】:

  • 谢谢,但我需要它在编译时的值,而不是错误,以便设置模板。想象一下模板 ::value> struct x{};
【解决方案3】:

为了应用编译时重载解析技巧来检测访问说明符,您至少需要在重载解析完成时考虑访问说明符。 C++03 不是这种情况,所以不能这样做。我相信 C++11 会改变这一点,因此通过一些人工转换和 SFINAE 您将能够实现它。

更新:我正在阅读 n3242 重载解决部分,我找不到任何表明访问说明符被认为是 C++11 中的重载结果的任何内容.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-07
    • 2013-07-14
    • 2011-06-07
    • 2016-08-07
    • 2014-08-30
    • 2022-11-24
    • 2021-10-16
    • 1970-01-01
    相关资源
    最近更新 更多