我有一个包含私有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的大小或公开 什么现在私人?
答案 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);
}