0

That's my demo to illustrate:

#include <iostream>
#include <ostream>
#include <utility>

template <typename T>
bool f(int) {
    __builtin_unreachable();
}
template <>
bool f<int>(int) {
    return true;
}
template <>
bool f<float>(int) {
    return true;
}
template <>
bool f<double>(int) {
    return false;
}

enum class Ops { OR, AND, VOID };

template <Ops Op, typename T, typename... Ts>
bool call_for_multi_type(int arg) {
    if constexpr (sizeof...(Ts) == 0) {
        return f<T>(arg);
    } else {
        if constexpr (Op == Ops::OR) {
            return f<T>(arg) || call_for_multi_type<Op, Ts...>(arg);
        } else if constexpr (Op == Ops::AND) {
            return f<T>(arg) && call_for_multi_type<Op, Ts...>(arg);
        } else if constexpr (Op == Ops::VOID) {
            return (f<T>(arg), call_for_multi_type<Op, Ts...>(arg));
        } else {
            __builtin_unreachable();
        }
    }
}

int main() {
    std::cout << call_for_multi_type<Ops::AND, int, double, float>(1);
    std::cout << call_for_multi_type<Ops::OR, int, float, double>(1);
    std::cout << call_for_multi_type<Ops::OR, int, float>(1);
    std::cout << call_for_multi_type<Ops::OR, double>(1);
    return 0;
}

And now I want to make a new function based on it, which let f also could be specific in compile stage. That's to say, I have a dozen of template functions, not only f. and I can change my call from

call_for_multi_type<Ops::AND, int, double, float>(1)

to

call_for_multi_type<func1, Ops::AND, int, double, float>(1)

or

call_for_multi_type<func2, Ops::AND, int, double, float>(1)

and all of them have different signatures.

zclll
  • 77
  • 7
  • 1
    *"That's my demo to illustrate:"* -- to illustrate what? Questions are more effective when they present the question *before* any code (cf. [ask]). Forcing yourself to write out in words what you are are trying to do leads to less confusion, as different people often see the same piece of code differently. – JaMiT Mar 31 '23 at 05:51
  • 1
    Similar to [this question](https://stackoverflow.com/questions/4697180/template-function-as-a-template-argument). – seleciii44 Mar 31 '23 at 07:56

1 Answers1

0

You can't use a template function as a template template parameter, so just wrap it in a functor.

template<typename T> bool f2(int,double); // with 2 parameters
template<> bool f2<int>(int,double)    {return false;}
template<> bool f2<float>(int,double)  {return true;}
template<> bool f2<double>(int,double) {return true;}

template<typename T>
struct CFct_f {    // wrap f()
   auto  operator()(int i)const { return f<T>(i); }
};
template<typename T>
struct CFct_f2 {   // wrap f2(,)
   auto  operator()(int i,double d)const { return f2<T>(i,d); }
};

Then you can use it in a call_for_multi_type template.

template <template<typename>class CFct, Ops Op, typename T, typename... Ts, typename...Args>
bool call_for_multi_type(Args... args) {
   if constexpr (sizeof...(Ts) == 0) {
      return CFct<T>{}(std::forward<Args>(args)...);
   }
   else {
      if constexpr (Op == Ops::OR) {
         return CFct<T>{}(std::forward<Args>(args)...) || call_for_multi_type<CFct,Op, Ts...>(std::forward<Args>(args)...);
      }
      else if constexpr (Op == Ops::AND) {
         return CFct<T>{}(std::forward<Args>(args)...) && call_for_multi_type<CFct,Op, Ts...>(std::forward<Args>(args)...);
      }
      else if constexpr (Op == Ops::VOID) {
         return (CFct<T>{}(std::forward<Args>(args)...), call_for_multi_type<CFct,Op, Ts...>(std::forward<Args>(args)...));
      }
   }
}

int main() {
   std::cout << call_for_multi_type<CFct_f,Ops::AND, int, double, float>(1);
   std::cout << call_for_multi_type<CFct_f2,Ops::OR, int, float, double>(1,2.);
   std::cout << call_for_multi_type<CFct_f2,Ops::OR, int, float>(1,2.);
   std::cout << call_for_multi_type<CFct_f2,Ops::OR, double>(1,2.);
}
dalfaB
  • 436
  • 1
  • 7