使用标签调度时如何反向模板参数
How to reverse template parameters when tag dispatching is used?
我一直在使用标签调度来建模问题。
Note :此代码运行,我只是对不涉及太多编码的解决方案感兴趣,只是为了反转调度算法的参数。
这是所讨论的代码:
#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
接受更多参数时,其他算法会发生什么?
我个人会考虑使用过载,而不是多个类。而且您还需要以某种方式进行标签选择器。
让我们从标签选择器开始。
// 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);
}
因此,简而言之,所有这些都是 Just ,因此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。模糊(可能可以做更清洁),2。仅允许const&
目前的参数,这很烦人;可能有一种解决这两个问题的方法。
带有标签修改的订单:
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));
}
相关文章:
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 标准对此指向成员函数类型模板参数有何说明?是我的代码有误,还是 MSVS 16.6 有问题?
- 谷物/C++ 11 - 如何指定反序列化的可选参数
- "return-by-reference"或"pass-by-reference"参数何时与constexpr兼容?
- 我的函数及其参数在反汇编视觉 c++ 中的名称
- 反汇编函数参数(无符号__int8)大海捞针[19] << 8)
- 在不知道参数类型的情况下对lambda求反