重构 c++基于模板类型的模板类
给定 Foo 类,
template <typename T>
class Foo
{
public:
...other methods..
void bar()
{
...
m_impl.doSomething();
...
}
void fun()
{
...
m_impl.doSomethingElse();
...
}
void fubar()
{
...
}
private:
T m_impl;
};
我想满足 T 是 boost::shared_ptr 的情况。 在这种情况下,对 Foo 类的唯一更改是它应该调用,
m_impl->doSomething();
而不是
m_impl.doSomething();
我最终在同一个标头中定义 FooPtr
template <typename T>
class FooPtr
{
public:
...other methods..
void bar()
{
...
m_pImpl->doSomething();
...
}
void fun()
{
...
m_pImpl->doSomethingElse();
...
}
void fubar()
{
...
}
private:
boost::shared_ptr<T> m_pImpl;
};
现在,虽然该方法适用于我想与 Foo 一起使用的所有类, 问题是我有很多重复的代码以及任何更改 我对 Foo 进行了操作,我还必须对 FooPtr 进行操作。
我该如何重构代码?例如,有什么方法可以在编译时确定 T 是否属于 boost::shared_ptr 类型,然后专门化 bar 和 fun 方法来调用 ->操作员?
编辑: 感谢到目前为止所有的答案!我只需要一些时间来完成所有这些工作,看看哪种解决方案最适合我们的软件。
编辑2: @Matthieu:这是我正在使用的测试代码
class FooImpl
{
public:
void doIt()
{
cout << "A" << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Foo<FooImpl> foo;
foo.doSomething();
return 0;
}
Given class Foo
template <typename T>
class Foo
{
public:
...other methods..
void bar()
{
...
m_impl.doSomething();
...
}
void fun()
{
...
m_impl.doSomethingElse();
...
}
void fubar()
{
...
}
private:
T m_impl;
};
I wanted to cater for situations where T is a boost::shared_ptr.
In this case the only change to class Foo is that it should invoke
m_impl->doSomething();
instead of
m_impl.doSomething();
I ended up defining FooPtr in the same header
template <typename T>
class FooPtr
{
public:
...other methods..
void bar()
{
...
m_pImpl->doSomething();
...
}
void fun()
{
...
m_pImpl->doSomethingElse();
...
}
void fubar()
{
...
}
private:
boost::shared_ptr<T> m_pImpl;
};
Now while the approach works for all classes that I want to use with Foo,
the problem is that I have a lot of duplicate code lying around and any changes
I make to Foo, I also have to make to FooPtr.
How can I refactor the code? E.g. Is there any way that I can determine at compile time if T is of type boost::shared_ptr, and then specialise just the bar and fun methods to invoke the -> operator?
Edit:
Thanks for all the answers so far! I just need some time to work through them all and see which solution is the best fit for our software.
Edit 2:
@Matthieu: This is the test code I was using
class FooImpl
{
public:
void doIt()
{
cout << "A" << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Foo<FooImpl> foo;
foo.doSomething();
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
Sylvain 编写了一个 DRY 解决方案,但我不喜欢滥用继承。
使用包装类来统一接口很容易,特别是因为指针语义工作得很好!
在这里,依靠提供OptionalPointee语义的
boost::Optional
,我们几乎得到了与指针相同的行为。但我想强调的一点是复制行为的差异。
boost::Optional
提供深度复制。Sylvain wrote a DRY solution, but I don't like abusing inheritance.
Using a wrapper class to uniformize the interface is easy, especially since pointer semantics work so well!
Here, relying on
boost::optional
which provides the OptionalPointee semantics, we nearly get the same behavior than pointers.One point I'd like to emphasize though, is the difference in the copying behavior.
boost::optional
provides deep copy.您可以编写一个
caller
类模板,其工作是使用语法obj.f()
或obj->f()< 来调用函数/code>,基于
obj
的类型。下面是一个演示此方法的小示例:
此示例类使用了此
caller
类模板:请参阅 ideone 上的在线运行演示:http://www.ideone.com/H18n7
--
编辑:
这更加通用。在这里您甚至可以在
caller
中传递您想要调用的函数。现在,caller
并未与要调用的函数进行硬编码!http://www.ideone.com/83H52
You can write a
caller
class template, whose job is to call the function, either using syntaxobj.f()
orobj->f()
, based on the type ofobj
.Here is a small example that demonstrates this approach:
And this
caller
class template is used by this sample class:See this online running demo at ideone : http://www.ideone.com/H18n7
--
EDIT:
This is even more generic. Here you can even pass the function which you want to call in
caller
. Nowcaller
is not hard-coded with the function to be called!http://www.ideone.com/83H52
我真的怀疑你是否应该在这里使用模板。您的模板参数具有非常清晰的接口,因此看起来您应该只使用抽象基类。
您真的需要一个实例吗?如果您确实需要更改对象的表示方式,则应将其作为单独的练习来完成,而不是使用它的模板的一部分。
I really question whether you should be using a template here at all. Your template parameter has a very clear interface and therefore looks like you should just use an abstract base class.
Do you really need to have an instance? If you do need to change the way the object is represented, this should be done as a separate exercise and not part of the template that uses it.
您可以引入另一个中间模板类,如下所示:
现在,您只需编写
Foo
类一次。您可以通过对 FooBase 进行部分特化来将其专门化为其他智能指针类型。编辑:您还可以使用组合,而不是在
Foo
和FooBase
之间建立继承关系(在这种情况下,我可能会将其重命名为FooHelper
> 或类似的东西)。You can introduce another intermediate template class, something like that:
Now, you only have to code the
Foo
class only once. And you can specialize it for other smart pointers type by doing partial specialization onFooBase
.Edit: You can also use composition instead of having an inheritance relationship between
Foo
andFooBase
(in which case, I'd probably rename it toFooHelper
or something like that).您可以使用部分专业化。
You can use partial specialization.