我想知道以下两个版本中的哪一个应该用于标签调度。我在项目中遇到过这种情况,我想使用最好的解决方案。标准中的实现使用第一种解决方案,但我想知道为什么以及效率的影响,如果有的话。
struct tag1{};
struct tag2{};
struct A{
using tag = tag1;
};
struct B{
using tag = tag2;
};
template<typename Tag>
struct Dispatcher;
template<typename T>
void dispatch(T a){
dispatch(a, T::tag()); ////// Solution 1
Dispatcher<typename T::tag>::dispatch(a); //////Solution 2
}
第一个解决方案:
/////////////////Solution 1///////////////////
template<typename T>
void dispatch(T a, tag1){
std::cout << "tag1 selected" << std::endl;
}
template<typename T>
void dispatch(T a, tag2){
std::cout << "tag2 selected" << std::endl;
}
/////////////////Solution 1///////////////////
第二个解决方案:
/////////////////Solution 2///////////////////
template<>
struct Dispatcher<tag1>{
template<typename T>
static void dispatch(T a){
std::cout << "tag1 selected" << std::endl;
}
};
template<>
struct Dispatcher<tag2>{
template<typename T>
static void dispatch(T a){
std::cout << "tag2 selected" << std::endl;
}
};
/////////////////Solution 2///////////////////
答案 0 :(得分:1)
使用第一个。这实际上是标签调度,而另一个则不是。原因是标签调度使用函数重载规则来决定调用什么。标签可以相互继承,允许您创建在非常具体或非常抽象的层次上运行的函数。
您的第二种技术在许多情况下都很有用。了解它如何在boost.fusion和boost.mpl等地方使用。它不是标签调度,所以如果你知道你想要标签调度来解决你的问题那么你就是在使用第一种技术而不是第二种技术。
至于你应该用它来解决你的特定问题 - 不知道它是什么我不能说。
编辑:例如,在MPL中,它用于创建通用操作并允许您覆盖路径。所以对于喜欢开头&lt;&gt;元函数有一个你实现的begin_impl或begin_traits(不要回忆起名字,查找它),如下所示:
struct my_sequence_tag {};
namespace boost { namespace mpl {
template < >
struct begin_impl<my_sequence_tag>
{
template < typename Sequence >
struct apply { /* ... */ };
};
}}
Boost的开始&lt;&gt;然后实现这样的元函数:
template < typename Sequence >
struct begin
: begin_impl<typename Sequence::tag>::template apply<Sequence>
{};