2011-02-09 78 views
1

雖然嘗試應用基於策略的設計,我就死在這個(簡體):如何使策略指定一個成員變量類型?

template <class TPrintPolicy, typename T> 
struct A : private TPrintPolicy { 
    using TPrintPolicy::Print; 
    T t; 
    void Foo() { 
     Print(t); 
    } 
}; 

struct IntPolicy { 
    void Print(int n) { 
     std::cout << n << std::endl; 
    } 
}; 

int main(int argc, char* argv[]) { 
    A<IntPolicy, int> a; 
    a.Foo(); 
    return 0; 
} 

而這裏的問題:我應該如何重新定義A級,這樣將有可能只提供政策參數設置爲一個模板,讓它推斷T自身,就像這樣:

A<IntPolicy> a; 

Preferrably,策略定義不應該是複雜得多那麼就是現在。有任何想法嗎?

編輯:
我忘了提及,我不希望政策導出typedef。這當然是簡單的解決方案,但不能自己推斷T的類型?

+0

無關:`模板'僅僅是一個傳統的語法`模板`和它們之間沒有差別(和類型名稱是首選)。 – 2011-02-09 19:47:42

+0

@PiotrLegnica:謝謝,很高興知道! – dnlgl 2011-02-09 19:55:05

+0

在非常特殊的情況下,class和typename之間有區別,請參見[this](http://stackoverflow.com/questions/2023977/c-difference-of-keywords-typename-and-class-in-templates) – Errata 2011-02-09 20:04:25

回答

5

在給出策略數據類型的每個策略中都做一個typedef。

template <class TPrintPolicy> 
struct A : private TPrintPolicy { 
    using TPrintPolicy::Print; 
    typename TPrintPolicy::data_type t; 
    void Foo() { 
     Print(t); 
    } 
}; 

struct IntPolicy { 
    typedef int data_type; 
    void Print(int n) { 
     std::cout << n << std::endl; 
    } 
}; 

int main(int argc, char* argv[]) { 
    A<IntPolicy> a; 
    a.Foo(); 
    return 0; 
} 

編輯:就個人而言,我可能會使用一個typedef,即使它增加了一些重複,因爲我相信它使代碼更清晰。但是,如果你真的想避免它,你可以嘗試類似的東西。

#include <boost/typeof/typeof.hpp> 

template<typename T, typename Class> 
T DeduceArgumentType(void (Class::*ptr)(T)) {} 

template <class TPrintPolicy> 
struct A : private TPrintPolicy { 
    using TPrintPolicy::Print; 
    typedef BOOST_TYPEOF(DeduceArgumentType(&TPrintPolicy::Print)) data_type; 
    data_type t; 
    void Foo() { 
     Print(t); 
    } 
}; 

struct IntPolicy { 
    void Print(int n) { 
     std::cout << n << std::endl; 
    } 
}; 

int main(int argc, char* argv[]) { 
    A<IntPolicy> a; 
    a.Foo(); 
    return 0; 
} 

它可能還可以得到Boost.TypeTraits要做到這一點,但我不知道怎麼樣。

1

我想有幾種方法可以做到這一點,但不知道從哪裏來的,很難給出明確的答案。如果T總是取決於傳遞給模板類型,一種方法是定義一個typedef到IntPolicy所需的類型,並使用在A.定義您的打印類型

template <class TPrintPolicy> 
struct A : private TPrintPolicy { 
    using TPrintPolicy::Print; 

    typename TPrintPolicy::print_type t; 
    void Foo() { 
     Print(t); 
    } 
}; 

struct IntPolicy { 

    typedef int print_type; 
    void Print(int n) { 
     std::cout << n << std::endl; 
    } 
}; 

int main(int argc, char* argv[]) { 
    A<IntPolicy> a; 
    a.t = 45; 
    a.Foo(); 
    return 0; 
} 

可能有更強勁如何做到這一點,但又取決於你的整體設計。

1

我更喜歡Josh'es的答案,但如果政策可能的參數類型是已知的,你可以做類似this。我用過Loki圖書館的SFINAE和type lists

template<class Type, class Policy> 
struct CheckPrintMethod{ 
    typedef struct { char table[2]; } yes; 
    typedef char no; 

    template<typename U, void (U::*)(Type)> struct SFINAE {}; 

    template<class T> static yes func(SFINAE<T, &T::Print> *); 
    template<class T> static no func(...); 

    static const bool value = (sizeof(func<Policy>(0)) == sizeof(yes)); 
}; 

template<class H, class T> 
struct List{ 
    typedef H Head; 
    typedef T Tail; 
}; 

class NullType{}; 

template<bool, class Y, class N> 
struct ifelse{ 
    typedef N type; 
}; 

template<class Y, class N> 
struct ifelse<true, Y, N>{ 
    typedef Y type; 
}; 

template<class TypeList, class Policy> 
struct CheckReturnType{ 
    typedef typename ifelse< 
      CheckPrintMethod<typename TypeList::Head, Policy>::value, 
      typename TypeList::Head, 
      typename CheckReturnType<typename TypeList::Tail, Policy>::return_type 
      >::type return_type; 
}; 

template<class Policy> 
struct CheckReturnType<NullType, Policy>{ 
    typedef NullType return_type; 
}; 

template <class TPrintPolicy> 
struct A : private TPrintPolicy { 
    using TPrintPolicy::Print; 
    typedef List<int, List<char, List<string, NullType> > > PossibleTypesList; 
    typedef typename CheckReturnType<PossibleTypesList, TPrintPolicy >::return_type print_type; 
    print_type t; 
    A(print_type obj): t(obj) {} 
    void Foo() { 
     Print(t); 
    } 
}; 

struct IntPolicy { 
    void Print(int n) { 
     std::cout << "Int: " << n << std::endl; 
    } 
}; 

struct StringPolicy { 
    void Print(string str) { 
     std::cout << "String: " << str << endl; 
    } 
}; 

int main(int argc, char* argv[]) { 
    A< IntPolicy> a(3); 
    a.Foo(); 
    A<StringPolicy> b("test"); 
    b.Foo(); 
    return 0; 
} 
相關問題