2015-06-10 4 views
1

Я хотел бы, чтобы следующий код компилировался, когда foo получает что-либо, полученное из базы, иначе возникает ошибка компиляции. Я написал класс type-trait is_Base, потому что std::is_base_of не очень хорошо работает с моими шаблонами. Я рядом. Я получил его для работы с использованием static_passoff, но я бы не хотел его использовать. Итак, как можно написать enable_if без взлома static_passoff? Вот работает версия: http://coliru.stacked-crooked.com/a/6de5171b6d3e12fffind typename typename в параметре шаблона

#include <iostream> 
#include <memory> 

using namespace std; 

template < typename D > 
class Base 
{ 
public: 
    typedef D EType; 
}; 

template<class T> 
struct is_Base 
{ 
    using base_type = typename std::remove_cv<typename std::remove_reference<T>::type>::type; 

    template<class U> 
    static constexpr std::true_type test(Base<U> *) { return std::true_type(); } 
    static constexpr std::false_type test(...) { return std::false_type(); } 

    using value = decltype(test((T*)0)); 
}; 

template < typename A > 
using static_passoff = std::integral_constant< bool, A::value >; 

template <typename T, typename = typename std::enable_if< static_passoff< typename is_Base<T>::value >::value >::type > 
void foo(T const&) 
{ 
} 


class Derived : public Base<Derived> {}; 
class NotDerived {}; 


int main() 
{ 
    Derived d; 
    //NotDerived nd; 

    foo(d); 
    //foo(nd); // <-- Should cause compile error 

    return 0; 
} 
+0

'станд :: is_base_of не очень хорошо работает с моим ... stuff'. См. Статью 27 «Эффективный современный C++» Скотта Мейера. Вам нужно 'std :: is_base_of > :: значение'. – kfsone

+0

@kfsone 'Base' - это шаблон класса. – Barry

+0

Ну, вы поняли мою мысль. См. Http://ideone.com/d3Of8G – kfsone

ответ

2

Я не совсем уверен, что я понимаю ваш вопрос, учитывая, что ваш код работает. Но стилистически, для метафайлов, которые дают тип, этот тип следует называть type. Таким образом, вы должны иметь:

using type = decltype(test((T*)0)); 
     ^^^^ 

Или, чтобы избежать нулевого указателя-Cast-хак:

using type = decltype(test(std::declval<T*>())); 

Кроме того, ваш test не нуждается в определении. Просто декларация. Мы на самом деле не , вызываем, просто проверяя его тип возврата. Он не должен быть constexpr либо, так что это достаточно:

template<class U> 
static std::true_type test(Base<U> *); 
static std::false_type test(...); 

После того, как вы есть, что вы можете его псевдоним:

template <typename T> 
using is_Base_t = typename is_Base<T>::type; 

И использовать псевдоним:

template <typename T, 
      typename = std::enable_if_t< is_Base_t<T>::value>> 
void foo(T const&) 
{ 
} 
+0

Я определил функции, чтобы избавиться от предупреждений clang. Этот псевдоним очень похож на мой взлом. Разве нет способа просто сказать 'is_Base :: type :: value' внутри enable_if? – Cory

+0

@Cory Да. Введите именно это. – Barry

+0

Я получаю сообщение об ошибке. Я попытался добавить 'typename' в разных местах, но я думаю, что я просто не знаю формат propper. – Cory

0

После спотыкания в ответ в комментариях, я узнал, что могу просто использовать is_Base<T>::type::value без каких-либо typename ключевых слов. Когда я пытаюсь удалить static_passoff, я продолжал класть typename. Я всегда смешивался с этим. Во всяком случае, вот окончательный код с несколькими teaks от ответа Барри:

#include <iostream> 
#include <memory> 

using namespace std; 

template < typename D > 
class Base 
{ 
public: 
    typedef D EType; 
}; 

template<class T> 
struct is_Base 
{ 
    using base_type = typename std::remove_cv<typename std::remove_reference<T>::type>::type; 

    template<class U> 
    static constexpr std::true_type test(Base<U> *) { return std::true_type(); } 
    static constexpr std::false_type test(...) { return std::false_type(); } 

    using type = decltype(test(std::declval<T*>())); 
}; 

template <typename T, typename = typename std::enable_if< is_Base<T>::type::value >::type > 
void foo(T const&) 
{ 
} 


class Derived : public Base<Derived> {}; 
class NotDerived {}; 


int main() 
{ 
    Derived d; 
    //NotDerived nd; 

    foo(d); 
    //foo(nd); // <-- Should cause compile error 

    return 0; 
} 
+1

Несовершеннолетний, предполагая, что Барри не каменяет меня для комментария, вы можете уменьшить 'using base_type' до' using base_type = std :: decay_t 'или C++ 11' using base_type = typename std :: decay :: type; '(http://en.cppreference.com/w/cpp/types/decay) – kfsone

+0

@kfsone Я забираю это. Похоже, что «распад» был бы полезен здесь. – Cory

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