在尝试应用基于策略的设计时,我遇到了这个问题(简化):
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的类型吗?
答案 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;
}