我一直在使用tag dispatching来建模问题。
注意:这段代码运行,我只是对一个不涉及这么多编码的解决方案感兴趣,只是为了反转调度算法的参数。
以下是相关代码:
#include <iostream>
struct A_tag {};
struct B_tag {};
// Tag getter
template<typename Type>
struct get { typedef void tag; };
namespace dispatch {
template<typename T1, typename T2>
struct my_algorithm {};
template<>
struct my_algorithm<A_tag, B_tag>
{
template<typename P1, typename P2>
static void apply(P1 const& p1, P2 const& p2)
{
auto p1val = p1.value();
auto p2val = p2.someFunction();
std::cout << p1val << " " << p2val << std::endl;
}
};
//Specialization reversal: can this be made shorter?
//A lot of lines used just to reverse the algorithm.
template<>
struct my_algorithm<B_tag, A_tag>
{
template<typename P2, typename P1>
static void apply(P2 const & p2, P1 const & p1)
{
my_algorithm<typename get<P1>::tag, typename get<P2>::tag>::apply(p1, p2);
}
};
}
// First and Second are test classes.
class First
{
public:
double value() const { return 5; };
};
template<>
struct get<First>
{
typedef A_tag tag; // Expect First to behave as A
};
class Second
{
public:
double someFunction() const { return 6; };
};
template<>
struct get<Second>
{
typedef B_tag tag; // Expect Second behave as B
};
// Tag dispatcher.
template<typename P1, typename P2>
void my_algorithm(P1 const & p1, P2 const & p2)
{
dispatch::my_algorithm<typename get<P1>::tag, typename get<P2>::tag>::apply(p1, p2);
}
int main(int argc, const char *argv[])
{
First f;
Second s;
my_algorithm(f, s);
// Commutative algorithm.
my_algorithm(s,f);
return 0;
}
无论模板参数的顺序如何,某些调度算法的工作方式都相同。 dispatch::my_algorithm::apply
函数执行此示例中的所有工作。我已经设法使用dispatch :: my_algorithm类的完整模板特化来反转模板参数,并使用反向参数调用静态apply
函数。
可以更快地完成参数反转吗?即使我以某种方式设法打包并“调用它”,当apply
接受更多参数时,其他算法会发生什么?
答案 0 :(得分:1)
我个人会考虑使用重载,而不是那么多类。而且你还需要一个标签选择器。
让我们从标签选择器开始。
// Note: to start simply we assume that a tag is only ever present once
// if not, we just need to add an index.
template <typename Tag,
typename Type,
typename std::disable_if<same_type<Tag, typename get<Head>::tag>::type>
struct has_tag: std::false_type {};
template <typename Tag,
typename Type,
typename std::enable_if<same_type<Tag, typename get<Head>::tag>::type>
struct has_tag: std::true_type {};
template <typename Tag, typename Head, typename... Tail>
struct tag_selector {
using type = if_<has_tag<Tag, Head>,
Head,
typename tag_selector<Tag, Tail...>::type>;
}; // tag_selector
template <typename Tag>
struct tag_selector {}; // compile-time error if tag absent
// A helper function
template <typename Result, typename Head, typename... Tail>
auto tag_select_impl(std::true_type, Head const& head, Tail const&... tail)
-> Result const&
{
return Head;
}
template <typename Result, typename Head, typename NH, typename... Tail>
auto tag_select_impl(std::false_type, Head const&, NH const& nh, Tail const&... tail)
-> Result const&
{
return tag_select_impl<Result>(has_tag<Tag, NH>{}, nh, tail);
}
// And now the runtime function
template <typename Tag, typename Head, typename... Tail>
auto tag_select(Tag, Head const& head, Tail const&... tail) ->
typename tag_selector<Tag, Head, Tail...>::type const&
{
using Result = typename tag_selector<Tag, Head, Tail...>::type;
return tag_select_impl<Result>(has_tag<Tag, Head>{}, head, tail);
}
因此,简而言之,所有这些只是,以便tag_select(tag, args...)
返回与tag
匹配的第一个参数。好消息是它非常通用:)
然后,我们实际上可以实现该算法:
void internal_impl(First const& first, Second const& second) {
std::cout << first.value() << " " << second.someFunction() << "\n";
} // internal_impl
template <typename A, typename B>
void interface(A const& a, B const& b) {
internal_impl(tag_select(A_tag{}, a, b), tag_select(B_tag{}, a, b));
}
注意:标签选择是1. murky(可能做得更干净)和2.现在只允许const&
个参数,这很烦人;可能有办法解决这两个问题。
答案 1 :(得分:1)
通过修改标签来获得订单:
struct A_tag { static const int value = 0; };
struct B_tag { static const int value = 1; };
然后:
template <typename P1, typename P2>
struct ordered_type
{
private:
typedef typename get<P1>::tag tag_P1;
typedef typename get<P2>::tag tag_P2;
static const bool ordered = tag_P1::value <= tag_P2::value;
public:
typedef typename std::conditional<ordered, tag_P1, tag_P2>::type tag1;
typedef typename std::conditional<ordered, tag_P2, tag_P1>::type tag2;
typedef typename std::conditional<ordered, P1, P2>::type type1;
typedef typename std::conditional<ordered, P2, P1>::type type2;
static constexpr const type1& getFirst(const P1& p1, const P2& p2)
{
return std::get<ordered ? 0 : 1>(std::tie(p1, p2));
}
static constexpr const type2& getSecond(const P1& p1, const P2& p2)
{
return std::get<ordered ? 1 : 0>(std::tie(p1, p2));
}
};
您可以删除专业化逆转并编写代码调度程序:
// Tag dispatcher.
template<typename P1, typename P2>
void my_algorithm(P1 const & p1, P2 const & p2)
{
typedef ordered_type<P1, P2> h;
dispatch::my_algorithm<typename h::tag1,
typename h::tag2>::apply(h::getFirst(p1, p2),
h::getSecond(p1, p2));
}