2013-04-23 62 views
1

我試圖定義一個類模板,它可以在許多數據結構上執行一些輸入/輸出操作(通過運算符< <和>>來自另一個類)。模板類的隱式轉換

總之,我可以做例子:

vector<int> x; 
map<string,vector<vector<int>>> y; 
const int z = 42; 

FooStream fs; 

Foo<decltype(x)> fx(x); 
Foo<decltype(y)> fy(y); 
Foo<decltype(z)> fz(z); 

fs << fx << fy <<fz>> fy >> fx; 

我的問題是如何能達到這樣的:

vector<int> x; 
map<string,vector<vector<int>>> y; 
const int z = 42; 

FooStream fs; 

fs << x << y <<z>> y >> x; 
//error : no operator found which takes a right-hand operand of type 'std::vector<_Ty>' (or there is no acceptable conversion) 

FooStream ::運算< <和>>應該接受過類型T當專業化Foo < T>被定義時。

欲瞭解更多詳情,這是我的(簡體)代碼。

class FooBase1{ 
protected: 
    union p_type{const void *p1;void *p2;} p; 
public: 
    FooBase1(const void *v){p.p1 = v;}; 
    virtual void func1_() = 0; 
}; 

class FooBase2 : public FooBase1{ 
public: 
    FooBase2(void *v) : FooBase1(v){}; 
    virtual void func2_() = 0; 
}; 

template<typename T,typename Enable=void> 
class Foo{ 
public: 
    typedef void generic; 
}; 

template<typename T,typename E=void> struct is_generic        : std::false_type{}; 
template<typename T>     struct is_generic<T,typename Foo<T>::generic> : std::true_type {}; 

template<typename T,typename T2=void> struct enable_if_ng : enable_if<!is_generic<T>::value,T2> {}; 

template<typename T> struct get_foo_type   {}; 
template<typename T> struct get_foo_type<Foo<T> > {typedef T type;}; 

#define DECLARE_FOO_SPECIALIZATION(Type)\ 
template<>\ 
class Foo<Type> : public FooBase2{\ 
public:\ 
    Foo(Type &v) : FooBase2(&v){}\ 
    virtual void func1_(){func1(*(const Type *)p.p2);}\ 
    virtual void func2_(){func2(*(Type *)p.p2);}\ 
    static void func1(const Type&){/*user defined*/}\ 
    static void func2(Type&){/*user defined*/}\ 
}; 
    //friend FooStream& operator>>(FooStream& fs,Type &f){Foo<Type>(f).func2_();return fs;} doesn't work 

DECLARE_FOO_SPECIALIZATION(bool) 
DECLARE_FOO_SPECIALIZATION(int) 
DECLARE_FOO_SPECIALIZATION(long) 
DECLARE_FOO_SPECIALIZATION(float) 
DECLARE_FOO_SPECIALIZATION(double) 
DECLARE_FOO_SPECIALIZATION(string) 

template<typename T1> 
class Foo<vector<T1>,typename enable_if_ng<T1>::type> : public FooBase2{ 
public: 
    Foo(vector<T1> &v) : FooBase2(&v){} 
    virtual void func1_(){func1(*(const vector<T1> *)p.p2);} 
    virtual void func2_(){func2(*(vector<T1> *)p.p2);} 
    static void func1(const vector<T1>&){/*user defined*/} 
    static void func2(vector<T1>&){/*user defined*/} 
}; 

template<typename T1,typename T2> 
class Foo<map<T1,T2>,typename enable_if<!is_generic<T1>::value && !is_generic<T2>::value>::type> : public FooBase2{ 
public: 
    Foo(map<T1,T2> &v) : FooBase2(&v){} 
    virtual void func1_(){func1(*(const map<T1,T2> *)p.p2);} 
    virtual void func2_(){func2(*(map<T1,T2> *)p.p2);} 
    static void func1(const map<T1,T2>&){/*user defined*/} 
    static void func2(map<T1,T2>&){/*user defined*/} 
}; 

template<typename T1> 
class Foo<const T1,typename enable_if_ng<T1>::type> : public FooBase1{ 
public: 
    Foo(const T1 &v) : FooBase1(&v){} 
    virtual void func1_(){func1(*(const T1 *)p.p1);} 
    static void func1(const T1& v){Foo<T1>::func1(v);} 
}; 

class FooStream{ 
public: 
    FooStream(){}; 
    FooStream& operator<<(FooBase1 &f){f.func1_();return *this;}; 
    FooStream& operator>>(FooBase2 &f){f.func2_();return *this;}; 
}; 

(其他問題:我可以通過使用模板漂亮的東西取代我的宏DECLARE_FOO_SPECIALIZATION我應該改變我的類層次?)

謝謝。

+0

也許你可以嘗試使用括號來命令評估。 – 0x499602D2 2013-04-23 23:15:55

+0

帖子名稱需要修復。這與帖子無關。 – 2013-04-23 23:22:56

+0

@ 0x499602D2:運營商<< and >>從左至右進行評估。但是當我只輸入1個參數時,我有相同的錯誤信息。 – Gilles 2013-04-23 23:42:40

回答

1

EnableIf並不在許多編譯器的工作,但你可以使用更粗SFINAE伎倆有:

template<std::size_t n> 
struct secret_enum { enum class type {}; }; 
template<bool b, std::size_t n = 0> 
using EnableIf = typename std::enable_if< b, typename secret_enum<n>::type >::type; 

template<typename T, bool b=true> 
struct can_be_fooed : std::false_type {}; 
template<typename T> 
struct can_be_fooed<T, std::is_same<Foo<T>, Foo<T>>::value>:std::true_type {}; 

class FooStream{ 
public: 

    template<typename T, EnableIf<can_be_fooed<typename std::decay<T>::type>>...> 
    FooStream& operator<<(T&&t){ 
    // body of <<, possibly involving wrapping the t in a Foo<T>? 
    }; 
}; 

當測試這種代碼,停在一行時做的事情15第一個會失敗。一次只測試一個步驟。使用模板元編程,您正在調試編譯步驟 - 通過以字節大小的塊編譯內容並在每個步驟中檢查,您正在完成相當於逐步執行代碼的步驟。


而不是你的宏,創建一個traits類,其中有問題的元素是具有true唯一的。然後,只需使用SFINAE編寫一個template,該文件僅針對這些類型打開。相同數量的代碼行,但沒有由宏生成的代碼。

template<typename T> struct do_stuff : std::false_type {}; 
template<> struct do_stuff<int> : std::true_type {}; 
template<> struct do_stuff<bool> : std::true_type {}; 
// yada yada 

template<typename T> 
class Foo<T, typename=typename std::enable_if< do_stuff<T>::value >::type> : public FooBase2 { 
public: 
    Foo(T &v) : FooBase2(&v){} 
    virtual void func1_(){func1(*(const T *)p.p2);} 
    virtual void func2_(){func2(*(T *)p.p2);}\ 
    static void func1(const T&){/*user defined*/}\ 
    static void func2(T&){/*user defined*/}\ 
};