使用模板公开私有Typedef

时间:2011-03-30 20:23:37

标签: c++ templates typedef

我有一个包含私有typedef和几个成员的类 功能:

class Foo
{
private:
  typedef std::blahblah FooPart;
  FooPart m_fooPart;
  ...
public:
  int someFn1();
  int someFn2();
};

有几个成员函数需要以类似的方式使用m_fooPart,所以我 想把它放在一个函数中。我把帮助函数放在匿名中 我可以随时使用命名空间,但在这种情况下,他们需要知道什么 FooPart是。所以,我做到了这一点:

namespace
{
  template <typename T>
  int helperFn(const T& foopart, int index)
  {
    ...
    return foopart.fn(index);
  }
}

int Foo::someFn1()
{
  ...
  return helperFn(m_fooPart, ix);       
}

通过强制编译器生成FooPart类型,我仍然在 行为明确的土地?是否有更优雅的方式 实现这一目标不会增加Foo的大小或公开 什么现在私人?

3 个答案:

答案 0 :(得分:4)

是的,这种方法产生了明确的,符合标准的行为。

也就是说,将一个成员函数添加到一个类中并不会增加一个类的大小(假设你的意思是sizeof运算符的结果),所以我不确定你在创建它时看到了什么缺点helper函数是Foo的私有成员。

答案 1 :(得分:3)

简单回答:将typedef设为公开。

这会泄漏实现的一个小细节(实际的内部类型),但因为它是typedefed,你可以随时重新定义它,它应该没问题。

稍微简单一点:与帮助函数保持联系,提供对内部类型的访问。

第二种方法的问题在于,您不仅要授予对typedef的访问权限,还要授予对类的所有私有部分的访问权限,这可能不是最好的主意。无论如何,因为这是一个内部辅助函数,它是你自己控制的,它应该没问题。 (现在我想起来了,您可能希望在命名空间中声明该函数,以使friend声明成功)

更简单:在实现文件中创建一个单独的typedef,并确保它们是同步的。

您可以通过一小部分元编程确保类型相同,same_type<T,U>模板如果两种类型相同则提供true值,否则为false。如果typedef只在一个地方发生变化,静态断言将触发错误

再次回到简单:​​提供typedef或直接使用类型而不使用静态断言。

您正在调用函数(这不应该是代码中的模板)并传递引用。如果类中的typedef发生更改,则调用将失败,编译器将告诉您。

我会选择最后一个选项,虽然它可能看起来有点粗糙而且精致比其他选项更多,事实是这只是一个其他人不使用的实现细节,你完全控制代码,简单就是更好。

评论后

编辑

我开始把它写成评论,但它变得太长了,所以我将它添加到答案中。

该解决方案本身没有任何问题,除了您不必要地使函数泛型,并且将来某些错误消息可能不像非通用签名那样简单。请注意,template公开typedef(如问题标题所示),而是会使编译器推断类型电话会议地点。

如果您更改typedef,而不是收到错误,指出helperFn的参数无法与现有函数匹配,则会推断出类型并且函数匹配,但您将获得如果您使用不再存在的类型的属性,则helperFn中的错误会更深。或者更糟糕的是,如果它是已更改类型的语义,您甚至可能不会收到错误。

考虑到typedef属于std::list<X>,并且在函数中使用这个简单正确的for循环迭代它:

for (typename T::iterator it=x.begin(), end=x.end(); it != end; ) {
   if ( condition(*it) ) 
      it = x.erase(it); 
   else 
      ++it; 
}

您能否发现将typedef更改为std::vector<X>会产生的影响?即使代码现在不正确,编译器也无法进行。是否像这样编写for循环是一个好主意,或者为什么不仅仅使用 erase-remove 成语是不同的问题(事实上前一个循环可以说更好< / em>比 erase-remove 列表),具体情况是语义已经改变,并且因为类型在语法上与前一个兼容,编译器将没有注意到代码是错误的,它不会指向你的功能,很可能你不会检查/重写它。

答案 2 :(得分:1)

我想这是泛型编程的想法 - 在不知道其类型的情况下使用Foo的一部分做事。 一个更“传统”(强类型,无聊,可读,代码复制 - 你的名字)的方式是明确提到类型:

int helperFn(const std::blahblah& foopart, int index)
{
    ...
    return foopart.fn(index);
}