1

I wrote a smal example illustrating the problem. solve_bs1_y and solve_bs2_y are implemented completely similar. The only difference is the function call: solve_bs*_z. Unfortunately, it seems impossible to pass a template as argument to replace the function call of solve_bs*_z. Consequently, I have to implement for each solve_bs*_z another solve_bs*_y. Is there a way to simplify the code so that I need just one implementation of solve_bs_y?

// Example program
#include <iostream>
#include <string>

template <int x, int y, int offs, class T>
float solve_bs1_z(T mat, float fS, float fT, float fU) {
  return 1; // to keep it simple
}

template <int x, int y, int offs, class T>
float solve_bs2_z(T mat, float fS, float fT, float fU) {
  return 2; // to keep it simple
}

// essentially the same as solve_bs2_y
template <int x, int offs, class T>
float solve_bs1_y(T mat, float fS, float fT, float fU) {
  const float bs_s = 2;

  return    ( solve_bs1_z<x, 0, offs>(mat, fS, fT, fU)
      + solve_bs1_z<x, 1, offs>(mat, fS, fT, fU)
      + solve_bs1_z<x, 2, offs>(mat, fS, fT, fU))
      * bs_s;
}
// essentially the same as solve_bs1_y
template <int x, int offs, class T>
float solve_bs2_y(T mat, float fS, float fT, float fU) {
  const float bs_s = 2;

  return    ( solve_bs2_z<x, 0, offs>(mat, fS, fT, fU)
      + solve_bs2_z<x, 1, offs>(mat, fS, fT, fU)
      + solve_bs2_z<x, 2, offs>(mat, fS, fT, fU) )
      * bs_s;
}

// these are called in the program ..
template<int offs, class T>
float solve_ffd_bs1(T mat, float fS, float fT, float fU) {
  return    solve_bs1_y<0, offs>(mat, fS, fT, fU) +
      solve_bs1_y<1, offs>(mat, fS, fT, fU) +
      solve_bs1_y<2, offs>(mat, fS, fT, fU);
}

template<int offs, class T>
float solve_ffd_bs2(T mat, float fS, float fT, float fU) {
  return    solve_bs2_y<0, offs>(mat, fS, fT, fU) +
      solve_bs2_y<1, offs>(mat, fS, fT, fU) +
      solve_bs2_y<2, offs>(mat, fS, fT, fU);
}


int main()
{
    int mat[3][3][3] = {
        {{1,2,3}, {4,5,6}, {7,8,9}},
        {{11,2,3}, {14,5,6}, {17,8,9}},
        {{21,2,3}, {24,5,6}, {27,8,9}}
        };


  solve_ffd_bs2<0>(mat, 1,2,3);

  return 0;
}
dgrat
  • 2,214
  • 4
  • 24
  • 46
  • are you looking for function pointers as template arguments? see e.g. here: https://stackoverflow.com/questions/1174169/function-passed-as-template-argument – 463035818_is_not_an_ai Jul 12 '17 at 11:38
  • _The only difference is the function call_. This means that they have the same body? It doesn't make much sense indeed. – skypjack Jul 12 '17 at 11:39
  • I cannot use function pointers because I use a template in the function I want to simplify. The template is resolved at place. – dgrat Jul 12 '17 at 11:40
  • 1
    @dgrat can you wrap stand-alone functions into static member functions? – W.F. Jul 12 '17 at 11:42
  • hm ok I didnt see that these are templates, but then why dont you turn `solve_bs1_z` and `solve_bs2_z` into `solve_bs_z` and `solve_bs_z` ? – 463035818_is_not_an_ai Jul 12 '17 at 11:43
  • @W.F. Then I still would need to resolve the type of the template struct :( – dgrat Jul 12 '17 at 11:43
  • @dgrat No, because you can pass a template template parameter (which you cannot use with function). – Holt Jul 12 '17 at 11:45
  • @dgrat not necessarily the struct can by itself be a non-template and serve as name to be passed to your related callee function – W.F. Jul 12 '17 at 11:45
  • Can you make an example whichs works in cpp.sh as me? – dgrat Jul 12 '17 at 11:46
  • @dgrat http://cpp.sh/5esvd – Holt Jul 12 '17 at 11:48
  • 1
    FYI: The code in the OP isn't exactly minimal. I think it hides what you're really trying to do. I made what I think is a better minimal case [here](https://wandbox.org/permlink/YYor0uXQIAj9uVLO) – AndyG Jul 12 '17 at 11:48

1 Answers1

5

The wrapper version without struct templates:

struct s1 {
    template <int x, int y, int offs, class T>
    static float solve_bs_z(T mat, float fS, float fT, float fU) {
      return 1; // to keep it simple
    }
};

struct s2 {
    template <int x, int y, int offs, class T>
    static float solve_bs_z(T mat, float fS, float fT, float fU) {
      return 2; // to keep it simple
    }
};

template <class Wrapper, int x, int offs, class T>
float solve_bs_y(T mat, float fS, float fT, float fU) {
  const float bs_s = 2;

  return    ( Wrapper::template solve_bs_z<x, 0, offs>(mat, fS, fT, fU)
      + Wrapper::template solve_bs_z<x, 1, offs>(mat, fS, fT, fU)
      + Wrapper::template solve_bs_z<x, 2, offs>(mat, fS, fT, fU))
      * bs_s;
}

and then call:

solve_bs_y<s1, 0, 1>(...);
W.F.
  • 13,888
  • 2
  • 34
  • 81
  • This solution is nice, I forgot about using structs.. But it is weird, that we need them. Why is the language not directly supporting struct-less approaches? – dgrat Jul 12 '17 at 12:37
  • @dgrat *"Why is the language not directly supporting struct-less approaches?"* It might have something to do with the fact that structs cannot be overloaded while functions (even those templated) can. Now when you will pass the name of overloaded templated function as sth like a template template parameter compiler might not be sure which overload is on your mind. – W.F. Jul 12 '17 at 18:32
  • @dgrat oh I forgot to add that I don't feel a language lawyer so I might be wrong :) When appropriately asked it could be a good question though! – W.F. Jul 12 '17 at 18:36
  • 1
    The language cannot directly support struct-less approaches because the language does not support partial template specialization for a function. AFAIK the reason it does this is because of function overloading (and function template overloading) Herb Sutter [has a good article on this](http://www.gotw.ca/publications/mill17.htm) – AndyG Jul 12 '17 at 20:28