Как определить, является ли тип видимой базой другого типа?
Если я делаю
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. Я хотел бы получить 0, когда C
является частным A
, а 1, когда C
является общедоступным A
.
[код получен из Как работает` is_base_of`?]
Ответы
Ответ 1
У вас есть доступ к компилятору с поддержкой С++ 11?
Если это так, вы можете комбинировать использование Chad static_cast
с decltype
, чтобы создать очень простую реализацию признаков типа (как показано в этом вопросе). Согласно предложению Джонатана Вакили, ссылки были заменены указателями, чтобы избежать ложных срабатываний, когда D
определяет operator B&()
.
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;
}
Ответ 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;
}
Ответ 3
Чтобы применить трюк разрешения перегрузки времени компиляции для обнаружения спецификаторов доступа, вам, по крайней мере, потребуется, чтобы спецификаторы доступа учитывались во время разрешения перегрузки. Это не относится к С++ 03, поэтому это невозможно. Я считаю, что С++ 11 меняет это на некоторые искусственные преобразования и SFINAE, которые вы могли бы реализовать.
Обновление: Я перехожу к разделу n3242 Overload Resolution, и я не могу найти ничего, что указывало бы на то, что спецификаторы доступа рассматриваются для получения перегрузки на С++ 11.