2011-02-09 1 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, чтобы это сделать вывод Т сама по себе, как это:

A<IntPolicy> a; 

Предпочтение будут определение политики не должно быть гораздо сложнее, чем сейчас. Есть идеи?

EDIT:
Я забыл упомянуть, что я не хочу, чтобы политика экспортировала typedef. Это, конечно, легкое решение, но не может ли вы сделать тип T сам по себе?

+0

Unrelated: '' шаблон просто наследство синтаксис '' шаблон и нет никакой разницы между ними (и имяТипом является предпочтительным). –

+0

@PiotrLegnica: Спасибо, приятно знать! – dnlgl

+0

В очень конкретном случае существует разница между классом и typename, см. [This] (http://stackoverflow.com/questions/2023977/c-difference-of-keywords-typename-and-class-in-templates) – Errata

ответ

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; 
} 

Edit: Лично я бы, вероятно, использовать ЬурейеЕ, даже если он добавляет некоторое дублирование, потому что я считаю, что это делает код гораздо понятнее. Однако, если вы действительно хотите этого избежать, вы можете попробовать что-то подобное этому.

#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, чтобы сделать это, но я не знаю, как.

+0

О, это было быстро, но, к сожалению, я забыл упомянуть, что я не хочу идти этим путем. Мое желание не упоминать тип T явно более одного раза (в объявлении Print()). Извините, и у вас есть upvote! – dnlgl

+0

@dnlgl, используйте typedef в методе «Печать», или, иначе, шаблон «IntPolicy», что-то вроде: 'template struct Policy {typedef DataType data_type; void Print (DataType n) {...}}; ', затем в' main', 'A > a;' – Nim

+0

@Nim, я подумал о шаблонах политики, но это было похоже на обман :-) Я действительно интересно, есть ли какое-либо решение этого без лишнего упоминания о явном типе T? – dnlgl

1

Я думаю, что есть несколько способов сделать это, но, не зная, откуда т приходит, трудно дать ясный ответ. Если T всегда зависит от типа передаваемого шаблона, один из способов заключаются в определении ЬурейеГо до нужного типа в IntPolicy, и использовать, чтобы определить, напечатанный тип в А.

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. Я использовал SFINAE и type lists из библиотеки Loki.

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; 
} 
+0

Это направление кажется многообещающим, но, к сожалению, в настоящее время оно требует упоминания явного типа в списке типов, что является одним из дополнительных упоминаний, которые я бы хотел избежать. Может быть полезно, хотя в случае, когда существует много политик с несколькими типами. – dnlgl

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