表示为struct的函数的部分评估 [英] Partial evaluation of a function represented as a struct

查看:110
本文介绍了表示为struct的函数的部分评估的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了允许自动区分,我将一个函数表示为struct

  template< GLuint i> 
struct x
{
static GLfloat eval(const GLfloat * o)
{
return o [i];
}
};

template< typename A,typename B>
struct ae
{
static GLfloat eval(const GLfloat * o){return A :: eval(o)+ B :: eval(o);}
};


其中 x< i& ; 表示一个参数。



但是,因为我需要


  1. 在开始时用常量替换一些参数

  2. 通过 x< i> 进行区分时,常量值

我应该如何实现部分求值,这样可以避免重复传递常量参数,并相应地简化函数结构? / p>

EDIT



我们有一个函数

  typedef ae< x< 0>,ae< x 1,x 2& f 

我知道 x <1> x <2> c <1> c < ; 2> )。
现在我想将 f 转换为 typedef ae< x< 0>,c> F

  struct c 
{
static GLfloat eval(const GLfloat * o){return c' + c 2;}
};

或类似的东西。

方案

这里是一些语法糖。



这是一个CRTP标签类型。给它一个更好的名字:

 模板< class T& 
struct my_tag {};

参与此游戏的每种类型都应继承自 my_tag< yourself& / code>。



接下来, x

 模板< GLuint i> 
struct x_t:my_tag< x_t< i>> {
GLfloat operator()(const GLfloat * o)const {
return o [i];
}
};

注意使用 operator() eval 。接下来是模板变量:

  template< GLuint i> 
constexpr x_t< i> x = {};

我们可能需要添加 constexpr x_t(){} x_t 取决于你的编译器。



这是一个通用操作:

  template< class Lhs,Rhs,class Op> 
struct op:my_tag< op< Lhs,Rhs,Op>> {
GLfloat operator()(const GLfloat * o)const {
return Op {}(Lhs {}(o),Rhs {}(o));
}
};

和我们的单行 add

 模板< class Lhs,Rhs& 
using add = op< Lhs,Rhs,std :: plus<>> C ++ 11中的

,我们必须写 std :: plus< void> 。在C ++ 03中,使用with替换 struct add:op< Lhs,Rhs,std :: plus<>> {}; $ c> plus<> 自己)。



现在我们重写 operator + 标有 my_tag 的标签的物件:

  template< class Lhs,Rhs& 
add< Lhs,Rhs> operator +(my_tag< Lhs>,my_tag< Rhs>){return {}; }

这为我们提供了一个不错的代数运算,

  auto f = x< 0> + x 1 + x 2; 

或者,如果我们想要类型

  decltype(x 0 + x 1 + x 2)f; 

...确定,我刚刚清理了您的系统。






下一个游戏是用常量替换变量。

  struct pi_constant {
constexpr GLfloat operator()(const GLfloat *)const {return 3.14; }
};

如果我们要替换 x< i>

  template< class Target,class Pattern ,class Result> 
struct replace {using type = Target; }
template< class Target,class Pattern,class Result>
使用replace_t = typename replace< Target,Pattern,Result> :: type;

template< class Pattern,class Result>
struct replace< Pattern,Pattern,Result> {
using type = Result;
};

template< template< class ...> class Z,class ... Ts,class Pattern,class Result>
struct replace< Z< Ts ...>,Pattern,Result> {
using type = Z< replace_t< Ts,Pattern,Result> ...,Pattern,Result&
};

replace_t< decltype(f),x_t',pi_constant> 将用常量 x < >



自然地,的值

c $ c> pi_constant 必须在编译时已知。



...



现在,如果你不知道编译时的值,一种方法可能是让你的变量不是一个,而是两个数组。然后你可以使用上面的替代方法来交换你正在阅读的两个数组中的哪一个。


In order to allow automatic differentiation, I represent a function as a struct

template <GLuint i>
struct x 
{
   static GLfloat eval (const GLfloat * o)
   {
      return o [i];
   }
};

template <typename A, typename B>
struct ae
{
   static GLfloat eval (const GLfloat * o) {return A :: eval (o) + B :: eval (o);}
};

etc.

where x <i> denotes a parameter.

However, since I need to

  1. Replace some parameters with constants at the beginning
  2. When differentiating by x <i>, set remaining parameters at constant value

how should I implement partial evaluation, so that repeatedly passing constant arguments can be avoided and the function structure is simplified accordingly?

EDIT

We have a function

typedef ae <x <0>, ae <x <1>, x <2>>> f

I know the values of x <1> and x <2> (c <1>, c <2>). Now I want f transformed into typedef ae <x <0>, c> F

struct c
{
   static GLfloat eval (const GLfloat * o) {return c <1> + c <2>;}
};

or something similar.

解决方案

Here is some syntax sugar to start.

This is a CRTP tag type. Give it a better name:

template<class T>
struct my_tag {};

Every type that participates in this game should inherit from my_tag<themselves>.

Next, an x:

template<GLuint i>
struct x_t : my_tag<x_t<i>> {
  GLfloat operator()(const GLfloat * o) const {
    return o[i];
  }
};

notice the use of operator() instead of eval. Next, a template variable:

template<GLuint i>
constexpr x_t<i> x = {};

we may need to add constexpr x_t() {} to x_t depending on your compiler.

This is a generic operation:

template<class Lhs, class Rhs, class Op>
struct op : my_tag<op<Lhs, Rhs, Op>> {
  GLfloat operator()(const GLfloat* o) const {
    return Op{}( Lhs{}(o), Rhs{}(o) );
  }
};

and our one-line add:

template<class Lhs, class Rhs>
using add = op<Lhs, Rhs, std::plus<>>;

in C++11, we have to write std::plus<void>. In C++03 replace using with can instead struct add:op<Lhs,Rhs,std::plus<>>{}; (and write plus<> ourselves).

Now we override operator+ on things tagged with my_tag:

template<class Lhs, class Rhs>
add<Lhs, Rhs> operator+( my_tag<Lhs>, my_tag<Rhs> ) { return {}; }

this gives us a nice algebra of operations that is less awkward to work with.

auto f = x<0>+x<1>+x<2>;

or, if we want the type

decltype(x<0>+x<1>+x<2>) f;

... ok, I've just cleaned up your system.


The next game is to replace variables with constants.

struct pi_constant {
  constexpr GLfloat operator()(const GLfloat*)const { return 3.14; }
};

if we want to replace our x<i> with that, we just have to do a search and replace of the template type.

template<class Target, class Pattern, class Result>
struct replace { using type=Target; }
template<class Target, class Pattern, class Result>
using replace_t = typename replace<Target, Pattern, Result>::type;

template<class Pattern, class Result>
struct replace<Pattern, Pattern, Result>{
  using type=Result;
};

template<template<class...>class Z, class...Ts, class Pattern, class Result>
struct replace<Z<Ts...>, Pattern, Result>{
  using type=Z<replace_t<Ts, Pattern, Result>..., Pattern, Result>;
};

and replace_t< decltype(f), x_t<1>, pi_constant > will replace all instances of x<1> with the constant pi_constant in f's expression tree.

Naturally the value of pi_constant has to be known at compile time.

...

Now, if you don't know the values at compile time, one approach might be to have your variables take not one, but two arrays. Then you can use the substitute trick above to swap which of the two arrays you are reading.

这篇关于表示为struct的函数的部分评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆