可以为特定的一组不同类型编写一次代码吗?

时间:2014-12-27 16:43:58

标签: c++11

我有一个模板类TC,其构造函数接受了值所依赖的参数,以及Tn类型。

所以,我想创建一个帮助器模板函数htf,它将调用Tn对象的相同函数,为一组类型TC生成X0Xn。辅助函数只从该集合中获取一个参数。是否有可能使用可变参数模板为函数集编写一次函数,而不是必须为每种类型反复写入相同的函数?

现在,我可以使用一个模板来允许所有类型,但我不想这样,因为可能会有另一个具有相同名称的函数,以后会针对特定类型编写,而不是基于此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函数适用于类X0X1X2,而不是Y0。但是,我不希望它干扰任何其他名为htf的函数,该函数采用Y0类型的参数,或其他任何类型的参数。

的其他

是否可以使接收类的集合也包含采用指定(或未指定)数量的参数的模板类?

2 个答案:

答案 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子句,这将是更好的,因为我有许多其他功能需要这个。

的其他

看起来这个答案不够好,因为我需要能够确定模板类是否在我正在寻找的集合中。