如何制定政策规定成员变量类型?

时间:2011-02-09 19:36:30

标签: c++ templates

在尝试应用基于策略的设计时,我遇到了这个问题(简化):

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类,以便只能为A模板提供策略参数,让它自己推断T,如下所示:

A<IntPolicy> a;

首先,政策定义不应该比现在复杂得多。有什么想法吗?

编辑:
我忘了提到我不希望策略导出typedef。这当然是简单的解决方案,但不能自己推断T的类型吗?

3 个答案:

答案 0 :(得分: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 :(得分:1)

我想有几种方法可以做到这一点,但不知道从哪里来,很难给出明确的答案。如果T始终依赖于传递给模板的类型,一种方法是在IntPolicy中将typedef定义为所需类型,并使用它在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;
}

可能有更强大的方法可以做到这一点,但同样取决于您的整体设计。

答案 2 :(得分: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;
}