2014-07-05 70 views
-2

我已經掃描了答案,但是...他們似乎是愚蠢的問題。C++ :: std :: enable_if和虛擬

我非常高興並充分理解(我不能強調這一點)與爲什麼沒有意義擁有一個類的模板虛擬成員。

考慮抽象基類List(與... LinkedListArrayList從中獲取)

如果該類型的列表存儲有身份的,沒有任何合理的「概念(不是字符串或整型,東西= =」,我不會把POD在這裏)你想一個方法
virtual bool contains(T& what) const;
virtual int index(T& what) const;
但 如果它是一種沒有身份,如字符串或數字,你會想:
virtual int countOccurrences(T& what) const;
virtual int find(T& what, int occurrence=0) const;

說。

這不能使用::std::enable_if所以你必須做這樣的事情要做:

template<class T, bool HAS_IDENTITY> class List; 
template<class T> class List<false> { 
    virtual int countOccurrences(T& what) const=0; 
    virtual int find(T& what, int occurrence=0) const=0; 
    /*other stuff*/ 
}; 

template<class T> class List<true> { 
    virtual bool contains(T& what) const =0; 
    virtual int index(T& what) const =0; 
    /*other stuff*/ 
}; 

這並不壞,但有很多重複的代碼,我只淋溼(防乾燒)時我不得不。

如果我將通用代碼隱藏在基類中,它會更好一些。

我的問題涉及使用這種方法進行縮放,在這裏我們有一個布爾,給出2個專業化,假設我有n布爾然後有2^n個專業化,我看不到一個情況,我需要超過4 ,但仍然涉及16個班級! 8爲3,這不是很好。

假設我有一個枚舉和一個布爾,那麼我有2 *枚舉計數專精。

它快速增長。

此前我們已經使用宏來定義類,它會在類名中使用##運算符來基本上將其作爲模板進行破解。我必須說,雖然我很喜歡enable_if和朋友現在雖然...

有沒有一種模式有人可以告訴我會解決這個問題?

+0

所以*身份證*的概念,是指可以使用'比擬的任何類型==操作符'?我不明白你怎麼能'countOccurrences'爲一種不平等的類型,但我想這與回答你的問題無關。 – Praetorian

+0

@Praetorian http://en.wikipedia.org/wiki/Identity_%28object-oriented_programming%29字符串沒有身份,如果我給你在內存中不同位置的兩個字符串,他們不是獨特的,'== '可以明確地定義。具有**身份的類型**使得可能在比特上完全相同的事物明顯不同,考慮例如姓名和年齡表中的記錄,「身份證」或「身份證」可以將具有相同姓名的兩個人分開同樣的年齡。在GUI程序中,我可以打開兩個相同的框架,它們具有標識(並且明顯不同),這就是爲什麼sizeof(struct {})== 1的原因。 –

+0

所以@Praetorian在這種情況下,如果列表存儲的是具有身份的東西,例如「countOccurrences」和「find」都是愚蠢的,「contains」和「index」就非常合適。當「性能」這樣的現實世界發揮作用時,這個概念變得有點模糊:P一般來說:如果使用引用或指針是身份,那麼任何通過值傳遞的內容(使用C++)都缺乏身份。 –

回答

0

只是一個q & d黑客,但它應該提供一些提示。

不知何故,我知道,一個甚至可以擺脫那個醜陋的「虛擬」參數,但我沒有看到,現在

編輯七月六日

我做了ansatz使用起來更加無縫。 概念「身份」,有什麼問題揭幕戰顯然瞄準的編譯時間測試,將需要

//T t1, t2; 
(t1 == t2) == (&t1 == &t2); 

編譯時的測試,這是國際海事組織不可能的。 因此,我介紹了功能列表的概念,以便於手動指定這些功能。

#include <iostream> 
#include <typeinfo> 
#include <type_traits> 
#ifdef __GNUG__ 
#include <cxxabi.h> 
auto type_str = [](const std::type_info& ti) { 
    int stat; 
    return abi::__cxa_demangle(ti.name(), 0, 0, &stat); 
}; 
#else 
#warning untested 
auto type_str = [](const std::type_info& ti) { 
    return ti.name(); 
}; 
#endif 


typedef int Feature; 

const Feature HAS_IDENTITY = 1; 
const Feature HAS_FOOBAR = 2; 
const Feature HAS_NO_IDENTITY = -HAS_IDENTITY; 
const Feature HAS_NO_FOOBAR = -HAS_FOOBAR; 
const Feature _TERM_ = 0; 


template<typename T, Feature F> 
struct has_feature : std::false_type {}; 

template<int N , int M> 
struct is_greater { 
    constexpr static bool value = N > M; 
}; 

namespace detail { 
    template<class T, Feature... Fs> struct List {}; // primary template 
    template<class T, Feature F> 
    struct List<T,F> {}; 

    template<class T, Feature F, Feature... Fs> 
    struct List<T,F,Fs...> 
     : virtual public 
       std::conditional< 
        has_feature<T,F>::value, 
        List<T, F>, 
        List<T, -F> 
       >::type, 
     virtual public 
       std::conditional< 
        is_greater<sizeof...(Fs),0>::value, 
        List<T, Fs...>, 
        List<T, _TERM_> 
       > ::type {}; 

    template<class T> struct List<T, _TERM_> {}; 

    template<class T> 
    struct List<T,HAS_NO_FOOBAR> { 
     virtual std::string hello() const /* = 0;*/ { 
      return std::string("\"What the foo is FOOBAR?\", askes ") + type_str(typeid(T)); 
     } 
    }; 

    template<class T> 
    struct List<T,HAS_FOOBAR> { 
     virtual std::string hello() const /* = 0;*/ { 
      return std::string("\"For sure I'm FOOBAR\", says ") + type_str(typeid(T)); 
     } 
    }; 


    template<class T> 
    struct List<T,HAS_NO_IDENTITY> { 
     virtual int index(const T& what) const /* = 0;*/ { 
      return 137; 
     } 
    }; 

    template<class T> 
    struct List<T,HAS_IDENTITY> { 
     virtual int index(const T& what) const /* = 0;*/ { 
      return 42; 
     } 
    }; 

    template<typename T> 
    using Feature_Aware_List = List<T,HAS_IDENTITY,HAS_FOOBAR, /* all Features incuding*/_TERM_>; 
} //namespace detail 

template<typename T> 
using List = detail::Feature_Aware_List<T>; 

struct Gadget { 
    bool operator== (const Gadget& rhs) const { 
     return this == &rhs; 
    } 
};  

struct Gimmick { 
    bool operator== (const Gimmick& rhs) const { 
     return this == &rhs; 
    } 
};  

template<Feature F> 
struct FeatureList {}; 

template<> 
struct FeatureList<HAS_IDENTITY> 
    : public Gadget, 
     public Gimmick 
     /**/ 
{}; 

#include <valarray> 
template<> 
struct FeatureList<HAS_FOOBAR> 
    : public std::valarray<float> 
     /**/ 
{}; 

template<class T> 
struct has_feature<T, HAS_IDENTITY> 
    : public std::conditional< 
     std::is_base_of<T, FeatureList<HAS_IDENTITY>>::value, 
     std::true_type, 
     std::false_type 
    >::type {}; 

template<class T> 
struct has_feature<T, HAS_FOOBAR> 
    : public std::conditional< 
     std::is_base_of<T, FeatureList<HAS_FOOBAR>>::value, 
     std::true_type, 
     std::false_type 
    >::type {}; 


int main() { 
    List<Gadget> l1 ; 
    List<std::valarray<float>> l2; 
    std::cout << l1.hello() << " #" << l1.index(Gadget()) << std::endl; 
    std::cout << l2.hello() << " #" << l2.index(std::valarray<float>()) << std::endl; 

} 

輸出:

"What the foo is FOOBAR?", askes Gadget #42 
"For sure I'm FOOBAR", says std::valarray<float> #137 

它應該是自我解釋,沒有特定的 「列表」 的功能實現,這是模擬只

1

你可以使用模板政策:

template<class T, bool HAS_IDENTITY> class ListIdentityPolicy; 
template<class T> class ListIdentityPolicy<T, false> { 
    virtual int countOccurrences(T& what) const = 0; 
    virtual int find(T& what, int occurrence = 0) const = 0; 
}; 
template<class T> class ListIdentityPolicy<T, true> { 
    virtual bool contains(T& what) const = 0; 
    virtual int index(T& what) const = 0; 
}; 

template<class T, bool HAS_FOOBAR> struct ListFoobarPolicy; 
template<class T> struct ListFoobarPolicy<T, false> { 
    virtual void foo() = 0; 
}; 
template<class T> struct ListFoobarPolicy<T, true> { 
    virtual void bar() = 0; 
}; 

template <class T> class List 
    : public ListIdentityPolicy<T, HasIdentity<T>::value> 
    , public ListFoobarPolicy<T, HasFoobar<T>::value> 
{ 
public: 
    /*other stuff*/ 
}; 

HasIdentity and HasFoobar是您定義的類型特徵,每個特徵包含static const bool value,指示T是否具有相應的屬性。


或者,你可以給List非虛擬的公共API,並隱藏在實現動態調度:

template <class T> class List 
{ 
public: 
    enum Impl { 
     LinkedList = 0, 
     ArrayList, 
    }; 
    List(Impl i) : pimpl(makePimpl(i)) {} 
    List(List const& other) : pimpl(other.pimpl->clone()) 
    List& operator=(List const& other) { pimpl = other.pimpl->clone(); } 

    int count(T& what) const 
    { static_assert(! HasIdentity<T>::value, "oops"); return pimpl->count(what); } 
    int find(T& what, int n = 0) const 
    { static_assert(! HasIdentity<T>::value, "oops"); return pimpl->find(what, n); } 
    bool contains(T& what) const 
    { static_assert(HasIdentity<T>::value, "oops"); return pimpl->contains(what); } 
    int index(T& what) const 
    { static_assert(HasIdentity<T>::value, "oops"); return pimpl->index(what); } 
    void foo() 
    { static_assert(! HasFoobar<T>::value, "oops"); pimpl->foo(); } 
    void bar() 
    { static_assert(HasFoobar<T>::value, "oops"); pimpl->bar(); } 

private: 
    struct AbstractPimpl 
    { 
     virtual std::unique_ptr<AbstractPimpl> clone() const = 0; 
     virtual int count(T& what) const = 0; 
     virtual int find(T& what, int n = 0) const = 0; 
     virtual bool contains(T& what) const = 0; 
     virtual int index(T& what) const = 0; 
     virtual void foo() = 0; 
     virtual void bar() = 0; 
    }; 

    struct LinkedListPimpl : public AbstractPimpl 
    { 
     std::unique_ptr<AbstractPimpl> clone() override; 
     int count(T& what) const override; 
     int find(T& what, int n = 0) const override; 
     bool contains(T& what) const override; 
     int index(T& what) const override; 
     void foo() override; 
     void bar() override; 
     /* ... */ 
    }; 

    struct ArrayListPimpl : public AbstractPimpl 
    { 
     std::unique_ptr<AbstractPimpl> clone() override; 
     virtual int count(T& what) const override; 
     virtual int find(T& what, int n = 0) const override; 
     virtual bool contains(T& what) const override; 
     virtual int index(T& what) const override; 
     virtual void foo() override; 
     virtual void bar() override; 
     /* ... */ 
    }; 

    std::unique_ptr<AbstractPimpl> pimpl; 

    static std::unique_ptr<AbstractPimpl> makePimpl(Impl i) { 
     switch (i) { 
      LinkedList: default: 
      return std::make_unique<LinkedListPimpl>(); 
      ArrayList: 
      return std::make_unique<ArrayListPimpl>(); 
     } 
    } 
};