我有一个模板类TC
,其构造函数接受了值所依赖的参数,以及Tn
类型。
所以,我想创建一个帮助器模板函数htf
,它将调用Tn
对象的相同函数,为一组类型TC
生成X0
到Xn
。辅助函数只从该集合中获取一个参数。是否有可能使用可变参数模板为函数集编写一次函数,而不是必须为每种类型反复写入相同的函数?
现在,我可以使用一个模板来允许所有类型,但我不想这样,因为可能会有另一个具有相同名称的函数,以后会针对特定类型编写,而不是基于此TC
。而且,IIRC我认为 SFINAE 适用于成员函数,而不是纯函数。
这只是我脑海中的一个想法,这就是为什么这个问题非常笼统。然而,这里大致是我想到的,简化的,更具体和过于笼统的代码:
struct X0
{
int value;
int& fn() { return value; }
};
struct X1
{
double value;
double& fn() { return value; }
};
struct X2
{
float value;
float& fn() { return value; }
};
struct Y0 // don't accept this class in helper function
{
int value;
int& fn() { return value; }
};
template<typename T1, typename Tn>
class TC
{
T1* m_pT1;
Tn* m_pTn;
TC(T1* pT1, Tn* pTn) : m_pT1(pT1), m_pTn(pTn) {}
friend TC htf(Tn& tn);
public:
~TC() {}
};
// concrete functions:
TC<int, X0> htf(C0& x) { return TC<int, X0>(&x.fn(), &x); }
TC<double, X1> htf(C1& x) { return TC<double, X1>(&x.fn(), &x); }
TC<float, X2> htf(C2& x) { return TC<float, X2>(&x.fn(), &x); }
// or in an over generalized template function but it'll accept
// Y0 and others which I don't want:
template<typename X>
auto htf(X& x) -> TC<decltype(x.fn()), X>
{
return TC<decltype(x.fn()), X>(&x.fn(), &x);
}
所以我想要的htf
函数适用于类X0
,X1
和X2
,而不是Y0
。但是,我不希望它干扰任何其他名为htf
的函数,该函数采用Y0
类型的参数,或其他任何类型的参数。
是否可以使接收类的集合也包含采用指定(或未指定)数量的参数的模板类?
答案 0 :(得分:2)
编写一个仅在特征为真时启用的函数,然后将其专门用于所有需要的类型。
template<typename T>
struct enable_htf : std::false_type { };
template<>
struct enable_htf<X0> : std::true_type { };
template<>
struct enable_htf<X1> : std::true_type { };
// etc.
template<typename T, bool enable = enable_htf<T>::value>
struct htf_helper { };
template<typename T>
struct htf_helper<T, true>
{
using type = TC<decltype(std::declval<T&>().fn()), T>;
};
template<typename X>
typename htf_helper<X>::type
htf(X& x)
{
return { &x.fn(), &x };
}
但似乎你想要这样的东西:
template<typename Needle, typename... Haystack>
struct is_one_of;
template<typename Needle, typename Head, typename... Tail>
struct is_one_of<Needle, Head, Tail...>
: conditional<is_same<Needle, Head>::value, true_type,
is_one_of<Needle, Tail...>>::type
{ };
template<typename Needle>
struct is_one_of<Needle> : false_type
{ };
template<typename X,
typename Requires = typename enable_if<is_one_of<X, X0, X1, X2>::value>::type>
auto
htf(X& x) -> TC<decltype(x.fn()), X>
{
return { &x.fn(), &x };
}
但我个人认为,即使is_one_of
可以在其他地方重复使用,我也不会认为更清楚。
答案 1 :(得分:0)
这是我原始问题的更简化版本,但它涉及根据传递给它的类型启用模板函数,它是接受类型列表的一部分。
class A{};
class B{};
class C{};
class D{};
class collection1 : A, B, C {};
class collection2 : D {};
template<typename X>
typename std::enable_if<std::is_base_of<X, collection1>::value, X>::type fn(X x)
{
return X();
}
然后以下内容将适当地运作:
fn(A()); // works
fn(B()); // works
fn(C()); // works
fn(D()); // compile time failure
拥有这样的第二个功能:
template<typename X>
typename std::enable_if<std::is_base_of<X, collection2>::value, X>::type fn(X x)
{
return X();
}
会导致:
fn(A()); // works
fn(B()); // works
fn(C()); // works
fn(D()); // works
使用这种方法,我可以启用函数fn
来处理我想要的类型而不是其他类型,我可以轻松地编写列表。此外,这应该比迭代可变参数模板参数列表更快。
感谢Jonathan Wakely,您在我的思维过程中帮了很多忙。我只是认为这更简单,如果我使用一个帮助器模板来封装enable_if
子句,这将是更好的,因为我有许多其他功能需要这个。
看起来这个答案不够好,因为我需要能够确定模板类是否在我正在寻找的集合中。