C++元程序自动创建函数
C++ metaprogramming automatic function creation?
我不确定标题是否正确,但这是我的问题:
我想使用元编程来为特定的表达式创建函数。例如,假设我们有这样的代码:
template<typename T1, typename T2>
struct plus{
T1 func(T1 in1, T2 in2){ return in1 + in2; }
};
template<typename T1, typename T2, typename T3, typename expr>
struct wrap{
/* contain a func that can evaluate the expr */
};
程序员将编写下面的代码,以便为表达式创建一个函数:
wrap<int,int,int,plus<plus<int,int>,int> >::func(1,2,3); /*result should be 6*/
这可能吗?
谢谢。
#include <utility>
#include <tuple>
#include <cstddef>
struct arg
{
template <typename Arg1>
static constexpr decltype(auto) apply(Arg1&& arg1)
{
return std::forward<Arg1>(arg1);
}
static constexpr std::size_t arity = 1;
};
template <typename Type, Type value>
struct constant
{
static constexpr decltype(auto) apply()
{
return value;
}
static constexpr std::size_t arity = 0;
};
template <typename Lhs, typename Rhs>
struct plus
{
template <typename... Args>
static constexpr decltype(auto) apply(Args&&... args)
{
return _apply(std::make_index_sequence<Lhs::arity>{}, std::make_index_sequence<Rhs::arity>{}, std::tuple<Args&&...>(std::forward<Args>(args)...));
}
template <typename Tuple, std::size_t... Arity1, std::size_t... Arity2>
static constexpr decltype(auto) _apply(std::index_sequence<Arity1...>, std::index_sequence<Arity2...>, Tuple&& args)
{
return Lhs::apply(static_cast<typename std::tuple_element<Arity1, Tuple>::type>(std::get<Arity1>(args))...)
+ Rhs::apply(static_cast<typename std::tuple_element<Lhs::arity + Arity2, Tuple>::type>(std::get<Lhs::arity + Arity2>(args))...);
}
static constexpr std::size_t arity = Lhs::arity + Rhs::arity;
};
template <typename Lhs, typename Rhs>
struct multiply
{
template <typename... Args>
static constexpr decltype(auto) apply(Args&&... args)
{
return _apply(std::make_index_sequence<Lhs::arity>{}, std::make_index_sequence<Rhs::arity>{}, std::tuple<Args&&...>(std::forward<Args>(args)...));
}
template <typename Tuple, std::size_t... Arity1, std::size_t... Arity2>
static constexpr decltype(auto) _apply(std::index_sequence<Arity1...>, std::index_sequence<Arity2...>, Tuple&& args)
{
return Lhs::apply(static_cast<typename std::tuple_element<Arity1, Tuple>::type>(std::get<Arity1>(args))...)
* Rhs::apply(static_cast<typename std::tuple_element<Lhs::arity + Arity2, Tuple>::type>(std::get<Lhs::arity + Arity2>(args))...);
}
static constexpr std::size_t arity = Lhs::arity + Rhs::arity;
};
测试:
int main()
{
// (1 + 2) + 3 = 6
std::cout << plus<plus<arg, arg>, arg>::apply(1, 2, 3) << std::endl;
// (a + 5) + (2 * 6) = 9 + 12 = 21
int a = 4;
std::cout << plus<plus<arg, arg>, multiply<arg, constant<int, 6>>>::apply(a, 5, 2) << std::endl;
// ((1 * 2) * 3) * 4 = 24
std::cout << multiply<multiply<multiply<arg, arg>, arg>, arg>::apply(1, 2, 3, 4) << std::endl;
// 2 + (4 * 5) = 22
static_assert(plus<arg, multiply<arg, arg>>::apply(2, 4, 5) == 22, "!");
}
输出:
6
21
24
演示1
上面的解决方案可以改进,这样引入新的函子需要更少的精力,声明本身也更可读,如下所示:
#include <iostream>
#include <utility>
#include <tuple>
#include <cstddef>
template <std::size_t Arity>
struct expression
{
static constexpr std::size_t arity = Arity;
};
template <typename Expr, typename Rhs>
struct unary_expression : expression<Rhs::arity>
{
template <typename... Args>
static constexpr decltype(auto) apply(Args&&... args)
{
static_assert(sizeof...(Args) == unary_expression::arity, "Wrong number of operands!");
return Expr::eval(Rhs::apply(std::forward<Args>(args)...));
}
};
template <typename Expr, typename Lhs, typename Rhs>
struct binary_expression : expression<Lhs::arity + Rhs::arity>
{
template <typename... Args>
static constexpr decltype(auto) apply(Args&&... args)
{
static_assert(sizeof...(Args) == binary_expression::arity, "Wrong number of operands!");
return _apply(std::make_index_sequence<Lhs::arity>{}, std::make_index_sequence<Rhs::arity>{}, std::tuple<Args&&...>(std::forward<Args>(args)...));
}
template <typename Tuple, std::size_t... Arity1, std::size_t... Arity2>
static constexpr decltype(auto) _apply(std::index_sequence<Arity1...>, std::index_sequence<Arity2...>, Tuple&& args)
{
return Expr::eval(Lhs::apply(static_cast<typename std::tuple_element<Arity1, Tuple>::type>(std::get<Arity1>(args))...),
Rhs::apply(static_cast<typename std::tuple_element<Lhs::arity + Arity2, Tuple>::type>(std::get<Lhs::arity + Arity2>(args))...));
}
};
struct arg : expression<1>
{
template <typename Arg1>
static constexpr decltype(auto) apply(Arg1&& arg1)
{
return std::forward<Arg1>(arg1);
}
};
template <typename Type, Type value>
struct constant : expression<0>
{
static constexpr decltype(auto) apply()
{
return value;
}
};
template <typename Rhs>
struct negate : unary_expression<negate<Rhs>, Rhs>
{
template <typename Arg1>
static constexpr decltype(auto) eval(Arg1&& arg1)
{
return -std::forward<Arg1>(arg1);
}
};
template <typename Lhs, typename Rhs>
struct plus : binary_expression<plus<Lhs, Rhs>, Lhs, Rhs>
{
template <typename Arg1, typename Arg2>
static constexpr decltype(auto) eval(Arg1&& arg1, Arg2&& arg2)
{
return std::forward<Arg1>(arg1) + std::forward<Arg2>(arg2);
}
};
template <typename Lhs, typename Rhs>
struct minus : binary_expression<minus<Lhs, Rhs>, Lhs, Rhs>
{
template <typename Arg1, typename Arg2>
static constexpr decltype(auto) eval(Arg1&& arg1, Arg2&& arg2)
{
return std::forward<Arg1>(arg1) - std::forward<Arg2>(arg2);
}
};
template <typename Lhs, typename Rhs>
struct multiply : binary_expression<multiply<Lhs, Rhs>, Lhs, Rhs>
{
template <typename Arg1, typename Arg2>
static constexpr decltype(auto) eval(Arg1&& arg1, Arg2&& arg2)
{
return std::forward<Arg1>(arg1) * std::forward<Arg2>(arg2);
}
};
int main()
{
// (1 + 2) + 3 = 6
std::cout << plus<plus<arg, arg>, arg>::apply(1, 2, 3) << std::endl;
// ((a + 5) + (2 * 6)) - 5 = 16
int a = 4;
std::cout << minus<plus<plus<arg, arg>, multiply<arg, constant<int, 6>>>, constant<int, 5>>::apply(a, 5, 2) << std::endl;
// ((1 * 2) * 3) * 4 = 24
std::cout << multiply<multiply<multiply<arg, arg>, arg>, arg>::apply(1, 2, 3, 4) << std::endl;
// -((3 * 4) + (5 - 6)) = -11
static_assert(negate<plus<multiply<arg, arg>, minus<arg, arg>>>::apply(3, 4, 5, 6) == -11, "!");
}
演示2
当然。这些被称为"表达模板",你可以在这里找到SO的亮点。
早在90年代末,我就在POOMA系统上进行并行编程。不确定它是否已经更新到现代标准,但我看到它仍然可以在这里在线获得。POOMA的基础是一个名为PETE的"表达式模板引擎",它可以重新用于其他评估引擎。此处描述了皮特。使用C++11,所有这些工作都会简单得多,我相信也有类似的工作使用这些更新的功能。
相关文章:
- 如何创建函数管道,以便函数一个接一个地运行?
- 如何创建一个对象创建函数,该函数将由与其关联的名称调用?
- 创建函数变体向量时"No matching function for call"错误
- C++ 在映射中创建函数指针向量
- 以编程方式在 C++ 中创建函数
- 如何创建函数可能使用自定义可比C++?
- 编译错误,未创建函数/方法! 对于 brms 模型
- Cython 创建 C 函数别名
- 创建函数指针数组
- 动态创建函数并获取指针
- 混合模板类型的模板参数包(std::使用可选参数重新创建函数)
- 如何创建函数原型命名空间
- 无法创建函数数组
- 在为STD模板函数创建函数对象时,还要还原样板
- 是否可以在C++中声明基类,以便只能通过创建函数创建从它派生的类
- 将原始指针移动到已创建函数中的下一个字符
- qjsonObject如何创建函数
- 尝试在别人的代码中C++创建函数(A* 搜索)
- 在C++中通过模板包重新创建函数签名和调用
- 创建函数时接收"expected unqualified-id"