说我有一些代码:
void barA() { }
void barB() { }
void fooA() {
// Duplicate code...
barA();
// More duplicate code...
}
void fooB() {
// Duplicate code...
barB();
// More duplicate code...
}
int main() {
fooA();
fooB();
}
我想删除fooA
和fooB
之间的重复代码我可以使用多种动态技术,例如传入bool参数,传递函数指针或虚拟方法但是如果我想要的话编译时技术我可以做这样的事情:
struct A { };
struct B { };
template<typename Tag> void bar();
template<> void bar<A>() { }
template<> void bar<B>() { }
template<typename Tag> void foo() {
// Duplicate code
bar<Tag>();
// More duplicate code
}
int main() {
foo<A>();
foo<B>();
}
我已经介绍了两个空的&#34; Tag&#34;用于根据标记类指示要使用bar
以及模板化foo
和bar
的类。这似乎可以解决问题。问题:
修改
另一种可能性是使用bar
的函数重载而不是模板特化,并将标记类作为参数传递:
struct A { };
struct B { };
void bar(A) { }
void bar(B) { }
template<typename Tag> void foo() {
// Duplicate code
bar(Tag());
// More duplicate code
}
int main() {
foo<A>();
foo<B>();
}
答案 0 :(得分:6)
这不是标签调度。正如你在你的问题中正确地说的那样,如果你使用A
和B
的一些编译时间特性来区分这两者,然后用它来在两个不同的重载之间进行选择。
标记分发的一个很好的例子是std::advance
通常是如何实现的。函数的签名是
template< class InputIt, class Distance >
void advance( InputIt& it, Distance n );
如果 it
符合RandomAccessIterator的要求,则可以在单个操作中提前n
个位置。对于较小的迭代器,我们必须在循环中前进it
。因此,实现可能会执行类似以下操作:
namespace detail
{
template<class InputIt, class Distance>
void advance(InputIt& it, Distance n, std::random_access_iterator_tag)
{
it += n;
}
template<class InputIt, class Distance>
void advance(InputIt& it, Distance n, std::bidirectional_iterator_tag)
{
if(n < 0) {
while(n++) --it;
} else {
while(n--) ++it;
}
}
template<class InputIt, class Distance>
void advance(InputIt& it, Distance n, std::input_iterator_tag)
{
assert(n >= 0);
while(n--) ++it;
}
}
template< class InputIt, class Distance >
void advance( InputIt& it, Distance n )
{
detail::advance(it, n,
typename std::iterator_traits<InputIt>::iterator_category());
}
我不知道你正在做什么的具体名称。这只是一个人如何遵循DRY原则的例子。
如果bar
将A
和B
的实例作为参数,那么我将以不同的方式实现它。我没有让bar
成为一个功能模板,然后提供专业化,而是让重载解决方案为我完成工作。
void bar(A const&) { ... }
void bar(B const&) { ... }
但由于情况并非如此,提供明确的专业化似乎是正确的方法。