Ren Chen
Ren Chen

Reputation: 155

template function returning template function pointers

Currently I implemented two template functions, each returning a template function pointer wrapped using boost::variant:

  1. Function fa

    typedef boost::variant<&A<int>,&A<double>> A_T;
    
    A_T fa(string type)
    {
        switch(type){
            case "int":  return &A<int>;
            case "double": return &A<double>;
            default: return &A<int>;
        }
    }
    
  2. Function fb

    typedef boost::variant<&B<int>,&B<double>> B_T;
    
    B_T fb(string type)
    {
       switch(type){
           case "int":  return &B<int>;
           case "double": return &B<double>;
           default: return &B<int>;
       }
    }
    

My question is "Can we merge the two functions into one template function which takes the functor pointer of A or B as template parameter?". The reason why I need this is because I may have more than two functors like A and B.

Upvotes: 2

Views: 887

Answers (1)

HTNW
HTNW

Reputation: 29193

Simple:

template<template<typename> class F> // template template
using F_T = boost::variant<F<int>&, F<double>&>; // Need C++11 for this (not strictly needed) alias

template<template<typename> class F>
F_T<F> f(std::string type) {
  if(type == "double") return something<F<double>&>();
  else return something<F<int>&>();
}

using A_T = F_T<A>;
A_T at = f<A>("int");
// F_T<int> broken; // invalid: int is not a template<typename> class
// f<int>("int") // invalid: int is not a template<typename> class

A is template<typename> class, so it may be the type argument to F_T and f, which are both template<template<typename> class>. Compare having a function a => b and passing it as argument to a function (a => b) => c. We say that a function [](int i) { return i + 5; } has type int => int, just like a type template<typename> class A has kind * -> * (concrete type to concrete type). Just like higher-order functions can have types like (A => A) => A, higher-kinded types can have kinds like (* -> *) -> *, e.g. F_T. Normal types like int and A_T<A> which can be used as type of variables have kind *.

Theory aside, it's rather intuitive that you can have template template parameters like this, even if the syntax looks wonky at first.

Upvotes: 1

Related Questions