2015-04-09 5 views
3

У меня есть базовый классC++ проверка наследование во время компиляции

template<typename T> 
class Base {}; 

и несколько производных классов:

class DerivedInt : public Base<int> {} 
class DerivedDummy : public Base<Dummy> {} 
     // where Dummy is some user-defined concrete type 
template<typename E> 
class DerivedGeneric : public Base<E> {} 

Я хотел бы написать функцию f<DerivedType>::value типа признака, которая возвращает истину только тогда, когда существует тип T такой, что DerivedType наследуется от Base<T>.

Я чувствую, что SFINAE - это путь ... но я не слишком хорошо знаком с метапрограммированием черной магии. Благодаря!

ответ

1

Усовершенствование решения Mateusz Grzejek, чтобы сделать реальные черты:

template <class T> 
std::true_type is_derived_from_base_t_impl(const Base<T>* impl); 

std::false_type is_derived_from_base_t_impl(...); 

template <class Derived> 
using is_derived_from_base_t = 
    decltype(is_derived_from_base_t_impl(std::declval<Derived*>())); 

Live demo

Обратите внимание, что не обрабатывает множественное наследование.

+0

По какой-то причине я не могу использовать эту функцию типа в 'enable_if'. Что-то вроде 'typename std :: enable_if (), void> :: type' дает мне аргумент шаблона 1 недействителен. –

+1

@JimJarvis: работает с ':: value' ([demo] (http://ideone.com/hIUR5N)) – Jarod42

+1

или с' {} '([Demo] (http://ideone.com/j8VOrK)) , Кажется, что '()' вводит досадный синтаксический анализ. – Jarod42

1

Я не уверен, если std::is_base_of может быть полезным в этом случае, но вы, безусловно, можете использовать std::is_convertible.

Если существует тип T, так что Derived наследуется от Base<T>, это означает, что Derived является неявно преобразуемых в Base<T>.

Таким образом, вы можете просто использовать следующее решение. Это определение времени компиляции таким образом, что оно не будет компилироваться, если вы вызываете функцию проверки для типа, которая не соответствует вашим требованиям. Проверьте этот код:

#include <iostream> 


struct Dummy 
{ 
}; 

template<typename T> 
class Base 
{ 
}; 

class DerivedInt : public Base<int> 
{ 
}; 

class DerivedDummy : public Base<Dummy> 
{ 
}; 

template<typename E> 
class DerivedGeneric : public Base<E> 
{ 
}; 

template <class T> 
bool is_derived_from_base_t_impl(Base<T>* impl) 
{ 
    return true; 
} 

template <class Derived> 
bool is_derived_from_base_t() 
{ 
    Derived* d = nullptr; 
    return is_derived_from_base_t_impl(d); 
} 


int main() 
{ 
    std::cout<< is_derived_from_base_t<DerivedInt>() <<"\n"; 
    std::cout<< is_derived_from_base_t<DerivedDummy>() <<"\n"; 
    std::cout<< is_derived_from_base_t< DerivedGeneric<float> >() <<"\n"; 

    return 0; 
} 

Выход:

1 
1 
1 

Однако, если вы:

is_derived_from_base_t<float>(); 

Вы получите:

error C2784: 'bool is_derived_from_base_t_impl(Base<T> *)' : could not deduce template argument for 'Base<T> *' from 'float *'

(выход из VC++ 11)

+0

Его можно улучшить, чтобы вернуть false вместо ошибки компиляции, см. Мой ответ. – Jarod42

+0

Большое спасибо за ваше решение. Я предпочитаю код @ Jarod42, потому что я хочу использовать возвращаемое значение в static_assert() –

Смежные вопросы