Pass a template template argument without specifying the concrete type

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
7
down vote

favorite












I would like to implement a wrapper around a function call that would do something like this:



template <template<class> class F>
void Wrapper(int n, F&& f)

switch (n)

case 1:
f<std::int8_t>();
break;
case 2:
f<std::int16_t>();
break;
default:
break;



template <class T>
void func()

// ... body of func()



So that I would be able to make the following call in the code:



Wrapper(1, func);


But the abovementioned code doesn't compile because F&& f construct is invalid - I need to specify the concrete type of the argument. But if I make the function signature the following:



template <template<class> class F, class T>
void Wrapper(int n, F<T>&& f)


then I must make the call with the concrete type of f:



Wrapper(1, func<std::int8_t>);


and I won't be able to make a switch in Wrapper.



How can I implement the behaviour I need?










share|improve this question





















  • There is no way to do this unless n is known at compile time. Then, you could just make it a parameter, and call like Wrapper<1>(f). Not sure what you are trying to do here, but the example could also be achieved in better ways.
    – Dan M.
    3 hours ago














up vote
7
down vote

favorite












I would like to implement a wrapper around a function call that would do something like this:



template <template<class> class F>
void Wrapper(int n, F&& f)

switch (n)

case 1:
f<std::int8_t>();
break;
case 2:
f<std::int16_t>();
break;
default:
break;



template <class T>
void func()

// ... body of func()



So that I would be able to make the following call in the code:



Wrapper(1, func);


But the abovementioned code doesn't compile because F&& f construct is invalid - I need to specify the concrete type of the argument. But if I make the function signature the following:



template <template<class> class F, class T>
void Wrapper(int n, F<T>&& f)


then I must make the call with the concrete type of f:



Wrapper(1, func<std::int8_t>);


and I won't be able to make a switch in Wrapper.



How can I implement the behaviour I need?










share|improve this question





















  • There is no way to do this unless n is known at compile time. Then, you could just make it a parameter, and call like Wrapper<1>(f). Not sure what you are trying to do here, but the example could also be achieved in better ways.
    – Dan M.
    3 hours ago












up vote
7
down vote

favorite









up vote
7
down vote

favorite











I would like to implement a wrapper around a function call that would do something like this:



template <template<class> class F>
void Wrapper(int n, F&& f)

switch (n)

case 1:
f<std::int8_t>();
break;
case 2:
f<std::int16_t>();
break;
default:
break;



template <class T>
void func()

// ... body of func()



So that I would be able to make the following call in the code:



Wrapper(1, func);


But the abovementioned code doesn't compile because F&& f construct is invalid - I need to specify the concrete type of the argument. But if I make the function signature the following:



template <template<class> class F, class T>
void Wrapper(int n, F<T>&& f)


then I must make the call with the concrete type of f:



Wrapper(1, func<std::int8_t>);


and I won't be able to make a switch in Wrapper.



How can I implement the behaviour I need?










share|improve this question













I would like to implement a wrapper around a function call that would do something like this:



template <template<class> class F>
void Wrapper(int n, F&& f)

switch (n)

case 1:
f<std::int8_t>();
break;
case 2:
f<std::int16_t>();
break;
default:
break;



template <class T>
void func()

// ... body of func()



So that I would be able to make the following call in the code:



Wrapper(1, func);


But the abovementioned code doesn't compile because F&& f construct is invalid - I need to specify the concrete type of the argument. But if I make the function signature the following:



template <template<class> class F, class T>
void Wrapper(int n, F<T>&& f)


then I must make the call with the concrete type of f:



Wrapper(1, func<std::int8_t>);


and I won't be able to make a switch in Wrapper.



How can I implement the behaviour I need?







c++ templates template-templates






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 3 hours ago









undermind

887419




887419











  • There is no way to do this unless n is known at compile time. Then, you could just make it a parameter, and call like Wrapper<1>(f). Not sure what you are trying to do here, but the example could also be achieved in better ways.
    – Dan M.
    3 hours ago
















  • There is no way to do this unless n is known at compile time. Then, you could just make it a parameter, and call like Wrapper<1>(f). Not sure what you are trying to do here, but the example could also be achieved in better ways.
    – Dan M.
    3 hours ago















There is no way to do this unless n is known at compile time. Then, you could just make it a parameter, and call like Wrapper<1>(f). Not sure what you are trying to do here, but the example could also be achieved in better ways.
– Dan M.
3 hours ago




There is no way to do this unless n is known at compile time. Then, you could just make it a parameter, and call like Wrapper<1>(f). Not sure what you are trying to do here, but the example could also be achieved in better ways.
– Dan M.
3 hours ago












5 Answers
5






active

oldest

votes

















up vote
5
down vote













If you know func at compile time (that is, if it is not some function pointer), you can use the following solution:



template <template <class> typename F>
void Wrapper(int n)
switch (n)
case 1: F<std::int8_t>(); break;
case 2: F<std::int16_t>(); break;
default: break;



template <typename T>
void func() std::cout << sizeof(T) << std::endl;

template <typename T>
struct Func void operator()() func<T>(); ;

int main()
Wrapper<Func>(1);
Wrapper<Func>(2);






share|improve this answer



























    up vote
    1
    down vote













    You might rewrite your code to something like



    template <typename T> struct tag using type = T;;

    template <class F>
    void Wrapper(int n, F&& f)

    switch (n)

    case 1:
    f(tag<std::int8_t>());
    break;
    case 2:
    f(tag<std::int16_t>());
    break;
    default:
    break;



    template <class T>
    void func()

    // ... body of func()



    With usage:



    Wrapper(1, (auto t) return func<typename decltype(t)::type>());





    share|improve this answer



























      up vote
      0
      down vote













      Can you move int n to template parameter? Then you can use Int2Type idiom:



      template<int n> struct ParamType 
      using value = ... // here will be std::int8_t or std::int16_t depending on n


      template <template<class> class F, int n>
      void Wrapper(F f)
      f<ParamType<n>::value>();






      share|improve this answer






















      • F&& f doesn't compile anyway
        – undermind
        3 hours ago

















      up vote
      0
      down vote













      There are a few kinds of names in C++.



      There are values. There are types. There are functions (and methods). There are members. There are type templates. There are function templates. There are variable templates.



      These are not the official names in the standard.



      In template cases, when the template is instantiated you get the thing the template produces. So a type template when instantiated gives a type, etc.



      Members (functions and variables) can become values by becoming a pointer to a member function/value. Member variable names can become a value by pairing with an object, like foo.x.



      A function name can become a value by undergoing overload resolution. In some cases the function name is not overloaded, so the overload resolution is trivial.



      Etc.



      Function arguments are always values. They are never templates.



      Template arguments can be types, type templates or values.



      Your code is trying to pass a template as a value. You cannot do this without cheating. In your specific case, you want to pass a template function.



      Function templates are very much second class citizens in C++. You cannot pass a function template to any other template, nor can you pass them as a value. What you can do with them is highly limited.



      So we need to wrap up the template in something that can be passed around.



      Here is one approach:



      template<class T>struct tag_tusing type=T;;
      template<class T>constexpr tag_t<T> tag;
      template<class Tag>using type_t=typename Tag::type;

      auto func_template = (auto...tags)
      return (auto&&...args)->decltype(auto)
      return func< type_t<decltype(tags)>... >( decltype(args)(args)... );
      ;
      ;


      now func_template wraps a template function of kind template<class...Ts> R f(Args...) for nearly arbitrary types R, Args... and Ts...



      If we assume our argument is wrapped this way, we do this:



      template <class F>
      void Wrapper(int n, F&& f)

      switch (n)

      case 1:
      f(tag<std::int8_t>)();
      break;
      case 2:
      f(tag<std::int16_t>)();
      break;
      default:
      break;




      then at point of call we do:



      Wrapper( 2, func_template );


      and it works.



      We can generate func_template using macros:



      #define RETURNS(...) 
      noexcept(noexcept(__VA_ARGS__))
      ->decltype(__VA_ARGS__)
      return __VA_ARGS__;

      #define FUNC_TEMPLATE(...)
      (auto...tags)
      return (auto&&...args)
      RETURNS( __VA_ARGS__< type_t<decltype(tags)>... >( decltype(args)(args)... ) );



      and now we can change the call site to:



      Wrapper( 2, FUNC_TEMPLATE(func) );





      share|improve this answer



























        up vote
        0
        down vote














        and I won't be able to make a switch in Wrapper.



        How can I implement the behaviour I need?




        Unfortunately you can't pass a template function, to another function, without fix the template types.



        But there are many ways to do what you want using template classes (or structs).



        By example, following your request based on a template-template argument, you can put a static function inside a template struct (I suggest static, so you don't need to object of that type)



        template <typename>
        struct foo

        static void func ()

        // ... body of func()

        ;


        and you have to pass foo explicating it as template parameter



        Wrapper<foo>(1);
        Wrapper<foo>(2);


        Wrapper() become



        template <template <typename> class F>
        void Wrapper (int n)

        switch (n)

        case 1:
        F<std::int8_t>::func();
        break;
        case 2:
        F<std::int16_t>::func();
        break;
        default:
        break;




        Another way is make a not-template class/struct with a template method



        struct bar

        template <typename>
        static void func ()

        // ... body of func()

        ;


        that you can use in the same way



        Wrapper<bar>(1);
        Wrapper<bar>(2);


        or, if you prefer, in deducing the type using a bar object



        bar b0;

        Wrapper(bar, 1);
        Wrapper(b0, 2);


        In first case the signature for Wrapper is simply



        template <typename F>
        void Wrapper (int n)


        where in second case become



        template <typename F>
        void Wrapper (F const &, int n)


        In both case you have to explicate the template calling func()



         F::template func<std::int8_t>();

        // ...

        F::template func<std::int16_t>();





        share|improve this answer




















          Your Answer





          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52876034%2fpass-a-template-template-argument-without-specifying-the-concrete-type%23new-answer', 'question_page');

          );

          Post as a guest






























          5 Answers
          5






          active

          oldest

          votes








          5 Answers
          5






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          5
          down vote













          If you know func at compile time (that is, if it is not some function pointer), you can use the following solution:



          template <template <class> typename F>
          void Wrapper(int n)
          switch (n)
          case 1: F<std::int8_t>(); break;
          case 2: F<std::int16_t>(); break;
          default: break;



          template <typename T>
          void func() std::cout << sizeof(T) << std::endl;

          template <typename T>
          struct Func void operator()() func<T>(); ;

          int main()
          Wrapper<Func>(1);
          Wrapper<Func>(2);






          share|improve this answer
























            up vote
            5
            down vote













            If you know func at compile time (that is, if it is not some function pointer), you can use the following solution:



            template <template <class> typename F>
            void Wrapper(int n)
            switch (n)
            case 1: F<std::int8_t>(); break;
            case 2: F<std::int16_t>(); break;
            default: break;



            template <typename T>
            void func() std::cout << sizeof(T) << std::endl;

            template <typename T>
            struct Func void operator()() func<T>(); ;

            int main()
            Wrapper<Func>(1);
            Wrapper<Func>(2);






            share|improve this answer






















              up vote
              5
              down vote










              up vote
              5
              down vote









              If you know func at compile time (that is, if it is not some function pointer), you can use the following solution:



              template <template <class> typename F>
              void Wrapper(int n)
              switch (n)
              case 1: F<std::int8_t>(); break;
              case 2: F<std::int16_t>(); break;
              default: break;



              template <typename T>
              void func() std::cout << sizeof(T) << std::endl;

              template <typename T>
              struct Func void operator()() func<T>(); ;

              int main()
              Wrapper<Func>(1);
              Wrapper<Func>(2);






              share|improve this answer












              If you know func at compile time (that is, if it is not some function pointer), you can use the following solution:



              template <template <class> typename F>
              void Wrapper(int n)
              switch (n)
              case 1: F<std::int8_t>(); break;
              case 2: F<std::int16_t>(); break;
              default: break;



              template <typename T>
              void func() std::cout << sizeof(T) << std::endl;

              template <typename T>
              struct Func void operator()() func<T>(); ;

              int main()
              Wrapper<Func>(1);
              Wrapper<Func>(2);







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered 3 hours ago









              Daniel Langr

              5,5302041




              5,5302041






















                  up vote
                  1
                  down vote













                  You might rewrite your code to something like



                  template <typename T> struct tag using type = T;;

                  template <class F>
                  void Wrapper(int n, F&& f)

                  switch (n)

                  case 1:
                  f(tag<std::int8_t>());
                  break;
                  case 2:
                  f(tag<std::int16_t>());
                  break;
                  default:
                  break;



                  template <class T>
                  void func()

                  // ... body of func()



                  With usage:



                  Wrapper(1, (auto t) return func<typename decltype(t)::type>());





                  share|improve this answer
























                    up vote
                    1
                    down vote













                    You might rewrite your code to something like



                    template <typename T> struct tag using type = T;;

                    template <class F>
                    void Wrapper(int n, F&& f)

                    switch (n)

                    case 1:
                    f(tag<std::int8_t>());
                    break;
                    case 2:
                    f(tag<std::int16_t>());
                    break;
                    default:
                    break;



                    template <class T>
                    void func()

                    // ... body of func()



                    With usage:



                    Wrapper(1, (auto t) return func<typename decltype(t)::type>());





                    share|improve this answer






















                      up vote
                      1
                      down vote










                      up vote
                      1
                      down vote









                      You might rewrite your code to something like



                      template <typename T> struct tag using type = T;;

                      template <class F>
                      void Wrapper(int n, F&& f)

                      switch (n)

                      case 1:
                      f(tag<std::int8_t>());
                      break;
                      case 2:
                      f(tag<std::int16_t>());
                      break;
                      default:
                      break;



                      template <class T>
                      void func()

                      // ... body of func()



                      With usage:



                      Wrapper(1, (auto t) return func<typename decltype(t)::type>());





                      share|improve this answer












                      You might rewrite your code to something like



                      template <typename T> struct tag using type = T;;

                      template <class F>
                      void Wrapper(int n, F&& f)

                      switch (n)

                      case 1:
                      f(tag<std::int8_t>());
                      break;
                      case 2:
                      f(tag<std::int16_t>());
                      break;
                      default:
                      break;



                      template <class T>
                      void func()

                      // ... body of func()



                      With usage:



                      Wrapper(1, (auto t) return func<typename decltype(t)::type>());






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered 3 hours ago









                      Jarod42

                      109k1298173




                      109k1298173




















                          up vote
                          0
                          down vote













                          Can you move int n to template parameter? Then you can use Int2Type idiom:



                          template<int n> struct ParamType 
                          using value = ... // here will be std::int8_t or std::int16_t depending on n


                          template <template<class> class F, int n>
                          void Wrapper(F f)
                          f<ParamType<n>::value>();






                          share|improve this answer






















                          • F&& f doesn't compile anyway
                            – undermind
                            3 hours ago














                          up vote
                          0
                          down vote













                          Can you move int n to template parameter? Then you can use Int2Type idiom:



                          template<int n> struct ParamType 
                          using value = ... // here will be std::int8_t or std::int16_t depending on n


                          template <template<class> class F, int n>
                          void Wrapper(F f)
                          f<ParamType<n>::value>();






                          share|improve this answer






















                          • F&& f doesn't compile anyway
                            – undermind
                            3 hours ago












                          up vote
                          0
                          down vote










                          up vote
                          0
                          down vote









                          Can you move int n to template parameter? Then you can use Int2Type idiom:



                          template<int n> struct ParamType 
                          using value = ... // here will be std::int8_t or std::int16_t depending on n


                          template <template<class> class F, int n>
                          void Wrapper(F f)
                          f<ParamType<n>::value>();






                          share|improve this answer














                          Can you move int n to template parameter? Then you can use Int2Type idiom:



                          template<int n> struct ParamType 
                          using value = ... // here will be std::int8_t or std::int16_t depending on n


                          template <template<class> class F, int n>
                          void Wrapper(F f)
                          f<ParamType<n>::value>();







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited 3 hours ago

























                          answered 3 hours ago









                          Vladimir Berezkin

                          1,54541830




                          1,54541830











                          • F&& f doesn't compile anyway
                            – undermind
                            3 hours ago
















                          • F&& f doesn't compile anyway
                            – undermind
                            3 hours ago















                          F&& f doesn't compile anyway
                          – undermind
                          3 hours ago




                          F&& f doesn't compile anyway
                          – undermind
                          3 hours ago










                          up vote
                          0
                          down vote













                          There are a few kinds of names in C++.



                          There are values. There are types. There are functions (and methods). There are members. There are type templates. There are function templates. There are variable templates.



                          These are not the official names in the standard.



                          In template cases, when the template is instantiated you get the thing the template produces. So a type template when instantiated gives a type, etc.



                          Members (functions and variables) can become values by becoming a pointer to a member function/value. Member variable names can become a value by pairing with an object, like foo.x.



                          A function name can become a value by undergoing overload resolution. In some cases the function name is not overloaded, so the overload resolution is trivial.



                          Etc.



                          Function arguments are always values. They are never templates.



                          Template arguments can be types, type templates or values.



                          Your code is trying to pass a template as a value. You cannot do this without cheating. In your specific case, you want to pass a template function.



                          Function templates are very much second class citizens in C++. You cannot pass a function template to any other template, nor can you pass them as a value. What you can do with them is highly limited.



                          So we need to wrap up the template in something that can be passed around.



                          Here is one approach:



                          template<class T>struct tag_tusing type=T;;
                          template<class T>constexpr tag_t<T> tag;
                          template<class Tag>using type_t=typename Tag::type;

                          auto func_template = (auto...tags)
                          return (auto&&...args)->decltype(auto)
                          return func< type_t<decltype(tags)>... >( decltype(args)(args)... );
                          ;
                          ;


                          now func_template wraps a template function of kind template<class...Ts> R f(Args...) for nearly arbitrary types R, Args... and Ts...



                          If we assume our argument is wrapped this way, we do this:



                          template <class F>
                          void Wrapper(int n, F&& f)

                          switch (n)

                          case 1:
                          f(tag<std::int8_t>)();
                          break;
                          case 2:
                          f(tag<std::int16_t>)();
                          break;
                          default:
                          break;




                          then at point of call we do:



                          Wrapper( 2, func_template );


                          and it works.



                          We can generate func_template using macros:



                          #define RETURNS(...) 
                          noexcept(noexcept(__VA_ARGS__))
                          ->decltype(__VA_ARGS__)
                          return __VA_ARGS__;

                          #define FUNC_TEMPLATE(...)
                          (auto...tags)
                          return (auto&&...args)
                          RETURNS( __VA_ARGS__< type_t<decltype(tags)>... >( decltype(args)(args)... ) );



                          and now we can change the call site to:



                          Wrapper( 2, FUNC_TEMPLATE(func) );





                          share|improve this answer
























                            up vote
                            0
                            down vote













                            There are a few kinds of names in C++.



                            There are values. There are types. There are functions (and methods). There are members. There are type templates. There are function templates. There are variable templates.



                            These are not the official names in the standard.



                            In template cases, when the template is instantiated you get the thing the template produces. So a type template when instantiated gives a type, etc.



                            Members (functions and variables) can become values by becoming a pointer to a member function/value. Member variable names can become a value by pairing with an object, like foo.x.



                            A function name can become a value by undergoing overload resolution. In some cases the function name is not overloaded, so the overload resolution is trivial.



                            Etc.



                            Function arguments are always values. They are never templates.



                            Template arguments can be types, type templates or values.



                            Your code is trying to pass a template as a value. You cannot do this without cheating. In your specific case, you want to pass a template function.



                            Function templates are very much second class citizens in C++. You cannot pass a function template to any other template, nor can you pass them as a value. What you can do with them is highly limited.



                            So we need to wrap up the template in something that can be passed around.



                            Here is one approach:



                            template<class T>struct tag_tusing type=T;;
                            template<class T>constexpr tag_t<T> tag;
                            template<class Tag>using type_t=typename Tag::type;

                            auto func_template = (auto...tags)
                            return (auto&&...args)->decltype(auto)
                            return func< type_t<decltype(tags)>... >( decltype(args)(args)... );
                            ;
                            ;


                            now func_template wraps a template function of kind template<class...Ts> R f(Args...) for nearly arbitrary types R, Args... and Ts...



                            If we assume our argument is wrapped this way, we do this:



                            template <class F>
                            void Wrapper(int n, F&& f)

                            switch (n)

                            case 1:
                            f(tag<std::int8_t>)();
                            break;
                            case 2:
                            f(tag<std::int16_t>)();
                            break;
                            default:
                            break;




                            then at point of call we do:



                            Wrapper( 2, func_template );


                            and it works.



                            We can generate func_template using macros:



                            #define RETURNS(...) 
                            noexcept(noexcept(__VA_ARGS__))
                            ->decltype(__VA_ARGS__)
                            return __VA_ARGS__;

                            #define FUNC_TEMPLATE(...)
                            (auto...tags)
                            return (auto&&...args)
                            RETURNS( __VA_ARGS__< type_t<decltype(tags)>... >( decltype(args)(args)... ) );



                            and now we can change the call site to:



                            Wrapper( 2, FUNC_TEMPLATE(func) );





                            share|improve this answer






















                              up vote
                              0
                              down vote










                              up vote
                              0
                              down vote









                              There are a few kinds of names in C++.



                              There are values. There are types. There are functions (and methods). There are members. There are type templates. There are function templates. There are variable templates.



                              These are not the official names in the standard.



                              In template cases, when the template is instantiated you get the thing the template produces. So a type template when instantiated gives a type, etc.



                              Members (functions and variables) can become values by becoming a pointer to a member function/value. Member variable names can become a value by pairing with an object, like foo.x.



                              A function name can become a value by undergoing overload resolution. In some cases the function name is not overloaded, so the overload resolution is trivial.



                              Etc.



                              Function arguments are always values. They are never templates.



                              Template arguments can be types, type templates or values.



                              Your code is trying to pass a template as a value. You cannot do this without cheating. In your specific case, you want to pass a template function.



                              Function templates are very much second class citizens in C++. You cannot pass a function template to any other template, nor can you pass them as a value. What you can do with them is highly limited.



                              So we need to wrap up the template in something that can be passed around.



                              Here is one approach:



                              template<class T>struct tag_tusing type=T;;
                              template<class T>constexpr tag_t<T> tag;
                              template<class Tag>using type_t=typename Tag::type;

                              auto func_template = (auto...tags)
                              return (auto&&...args)->decltype(auto)
                              return func< type_t<decltype(tags)>... >( decltype(args)(args)... );
                              ;
                              ;


                              now func_template wraps a template function of kind template<class...Ts> R f(Args...) for nearly arbitrary types R, Args... and Ts...



                              If we assume our argument is wrapped this way, we do this:



                              template <class F>
                              void Wrapper(int n, F&& f)

                              switch (n)

                              case 1:
                              f(tag<std::int8_t>)();
                              break;
                              case 2:
                              f(tag<std::int16_t>)();
                              break;
                              default:
                              break;




                              then at point of call we do:



                              Wrapper( 2, func_template );


                              and it works.



                              We can generate func_template using macros:



                              #define RETURNS(...) 
                              noexcept(noexcept(__VA_ARGS__))
                              ->decltype(__VA_ARGS__)
                              return __VA_ARGS__;

                              #define FUNC_TEMPLATE(...)
                              (auto...tags)
                              return (auto&&...args)
                              RETURNS( __VA_ARGS__< type_t<decltype(tags)>... >( decltype(args)(args)... ) );



                              and now we can change the call site to:



                              Wrapper( 2, FUNC_TEMPLATE(func) );





                              share|improve this answer












                              There are a few kinds of names in C++.



                              There are values. There are types. There are functions (and methods). There are members. There are type templates. There are function templates. There are variable templates.



                              These are not the official names in the standard.



                              In template cases, when the template is instantiated you get the thing the template produces. So a type template when instantiated gives a type, etc.



                              Members (functions and variables) can become values by becoming a pointer to a member function/value. Member variable names can become a value by pairing with an object, like foo.x.



                              A function name can become a value by undergoing overload resolution. In some cases the function name is not overloaded, so the overload resolution is trivial.



                              Etc.



                              Function arguments are always values. They are never templates.



                              Template arguments can be types, type templates or values.



                              Your code is trying to pass a template as a value. You cannot do this without cheating. In your specific case, you want to pass a template function.



                              Function templates are very much second class citizens in C++. You cannot pass a function template to any other template, nor can you pass them as a value. What you can do with them is highly limited.



                              So we need to wrap up the template in something that can be passed around.



                              Here is one approach:



                              template<class T>struct tag_tusing type=T;;
                              template<class T>constexpr tag_t<T> tag;
                              template<class Tag>using type_t=typename Tag::type;

                              auto func_template = (auto...tags)
                              return (auto&&...args)->decltype(auto)
                              return func< type_t<decltype(tags)>... >( decltype(args)(args)... );
                              ;
                              ;


                              now func_template wraps a template function of kind template<class...Ts> R f(Args...) for nearly arbitrary types R, Args... and Ts...



                              If we assume our argument is wrapped this way, we do this:



                              template <class F>
                              void Wrapper(int n, F&& f)

                              switch (n)

                              case 1:
                              f(tag<std::int8_t>)();
                              break;
                              case 2:
                              f(tag<std::int16_t>)();
                              break;
                              default:
                              break;




                              then at point of call we do:



                              Wrapper( 2, func_template );


                              and it works.



                              We can generate func_template using macros:



                              #define RETURNS(...) 
                              noexcept(noexcept(__VA_ARGS__))
                              ->decltype(__VA_ARGS__)
                              return __VA_ARGS__;

                              #define FUNC_TEMPLATE(...)
                              (auto...tags)
                              return (auto&&...args)
                              RETURNS( __VA_ARGS__< type_t<decltype(tags)>... >( decltype(args)(args)... ) );



                              and now we can change the call site to:



                              Wrapper( 2, FUNC_TEMPLATE(func) );






                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered 2 hours ago









                              Yakk - Adam Nevraumont

                              173k19176357




                              173k19176357




















                                  up vote
                                  0
                                  down vote














                                  and I won't be able to make a switch in Wrapper.



                                  How can I implement the behaviour I need?




                                  Unfortunately you can't pass a template function, to another function, without fix the template types.



                                  But there are many ways to do what you want using template classes (or structs).



                                  By example, following your request based on a template-template argument, you can put a static function inside a template struct (I suggest static, so you don't need to object of that type)



                                  template <typename>
                                  struct foo

                                  static void func ()

                                  // ... body of func()

                                  ;


                                  and you have to pass foo explicating it as template parameter



                                  Wrapper<foo>(1);
                                  Wrapper<foo>(2);


                                  Wrapper() become



                                  template <template <typename> class F>
                                  void Wrapper (int n)

                                  switch (n)

                                  case 1:
                                  F<std::int8_t>::func();
                                  break;
                                  case 2:
                                  F<std::int16_t>::func();
                                  break;
                                  default:
                                  break;




                                  Another way is make a not-template class/struct with a template method



                                  struct bar

                                  template <typename>
                                  static void func ()

                                  // ... body of func()

                                  ;


                                  that you can use in the same way



                                  Wrapper<bar>(1);
                                  Wrapper<bar>(2);


                                  or, if you prefer, in deducing the type using a bar object



                                  bar b0;

                                  Wrapper(bar, 1);
                                  Wrapper(b0, 2);


                                  In first case the signature for Wrapper is simply



                                  template <typename F>
                                  void Wrapper (int n)


                                  where in second case become



                                  template <typename F>
                                  void Wrapper (F const &, int n)


                                  In both case you have to explicate the template calling func()



                                   F::template func<std::int8_t>();

                                  // ...

                                  F::template func<std::int16_t>();





                                  share|improve this answer
























                                    up vote
                                    0
                                    down vote














                                    and I won't be able to make a switch in Wrapper.



                                    How can I implement the behaviour I need?




                                    Unfortunately you can't pass a template function, to another function, without fix the template types.



                                    But there are many ways to do what you want using template classes (or structs).



                                    By example, following your request based on a template-template argument, you can put a static function inside a template struct (I suggest static, so you don't need to object of that type)



                                    template <typename>
                                    struct foo

                                    static void func ()

                                    // ... body of func()

                                    ;


                                    and you have to pass foo explicating it as template parameter



                                    Wrapper<foo>(1);
                                    Wrapper<foo>(2);


                                    Wrapper() become



                                    template <template <typename> class F>
                                    void Wrapper (int n)

                                    switch (n)

                                    case 1:
                                    F<std::int8_t>::func();
                                    break;
                                    case 2:
                                    F<std::int16_t>::func();
                                    break;
                                    default:
                                    break;




                                    Another way is make a not-template class/struct with a template method



                                    struct bar

                                    template <typename>
                                    static void func ()

                                    // ... body of func()

                                    ;


                                    that you can use in the same way



                                    Wrapper<bar>(1);
                                    Wrapper<bar>(2);


                                    or, if you prefer, in deducing the type using a bar object



                                    bar b0;

                                    Wrapper(bar, 1);
                                    Wrapper(b0, 2);


                                    In first case the signature for Wrapper is simply



                                    template <typename F>
                                    void Wrapper (int n)


                                    where in second case become



                                    template <typename F>
                                    void Wrapper (F const &, int n)


                                    In both case you have to explicate the template calling func()



                                     F::template func<std::int8_t>();

                                    // ...

                                    F::template func<std::int16_t>();





                                    share|improve this answer






















                                      up vote
                                      0
                                      down vote










                                      up vote
                                      0
                                      down vote










                                      and I won't be able to make a switch in Wrapper.



                                      How can I implement the behaviour I need?




                                      Unfortunately you can't pass a template function, to another function, without fix the template types.



                                      But there are many ways to do what you want using template classes (or structs).



                                      By example, following your request based on a template-template argument, you can put a static function inside a template struct (I suggest static, so you don't need to object of that type)



                                      template <typename>
                                      struct foo

                                      static void func ()

                                      // ... body of func()

                                      ;


                                      and you have to pass foo explicating it as template parameter



                                      Wrapper<foo>(1);
                                      Wrapper<foo>(2);


                                      Wrapper() become



                                      template <template <typename> class F>
                                      void Wrapper (int n)

                                      switch (n)

                                      case 1:
                                      F<std::int8_t>::func();
                                      break;
                                      case 2:
                                      F<std::int16_t>::func();
                                      break;
                                      default:
                                      break;




                                      Another way is make a not-template class/struct with a template method



                                      struct bar

                                      template <typename>
                                      static void func ()

                                      // ... body of func()

                                      ;


                                      that you can use in the same way



                                      Wrapper<bar>(1);
                                      Wrapper<bar>(2);


                                      or, if you prefer, in deducing the type using a bar object



                                      bar b0;

                                      Wrapper(bar, 1);
                                      Wrapper(b0, 2);


                                      In first case the signature for Wrapper is simply



                                      template <typename F>
                                      void Wrapper (int n)


                                      where in second case become



                                      template <typename F>
                                      void Wrapper (F const &, int n)


                                      In both case you have to explicate the template calling func()



                                       F::template func<std::int8_t>();

                                      // ...

                                      F::template func<std::int16_t>();





                                      share|improve this answer













                                      and I won't be able to make a switch in Wrapper.



                                      How can I implement the behaviour I need?




                                      Unfortunately you can't pass a template function, to another function, without fix the template types.



                                      But there are many ways to do what you want using template classes (or structs).



                                      By example, following your request based on a template-template argument, you can put a static function inside a template struct (I suggest static, so you don't need to object of that type)



                                      template <typename>
                                      struct foo

                                      static void func ()

                                      // ... body of func()

                                      ;


                                      and you have to pass foo explicating it as template parameter



                                      Wrapper<foo>(1);
                                      Wrapper<foo>(2);


                                      Wrapper() become



                                      template <template <typename> class F>
                                      void Wrapper (int n)

                                      switch (n)

                                      case 1:
                                      F<std::int8_t>::func();
                                      break;
                                      case 2:
                                      F<std::int16_t>::func();
                                      break;
                                      default:
                                      break;




                                      Another way is make a not-template class/struct with a template method



                                      struct bar

                                      template <typename>
                                      static void func ()

                                      // ... body of func()

                                      ;


                                      that you can use in the same way



                                      Wrapper<bar>(1);
                                      Wrapper<bar>(2);


                                      or, if you prefer, in deducing the type using a bar object



                                      bar b0;

                                      Wrapper(bar, 1);
                                      Wrapper(b0, 2);


                                      In first case the signature for Wrapper is simply



                                      template <typename F>
                                      void Wrapper (int n)


                                      where in second case become



                                      template <typename F>
                                      void Wrapper (F const &, int n)


                                      In both case you have to explicate the template calling func()



                                       F::template func<std::int8_t>();

                                      // ...

                                      F::template func<std::int16_t>();






                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered 1 hour ago









                                      max66

                                      30.4k63457




                                      30.4k63457



























                                           

                                          draft saved


                                          draft discarded















































                                           


                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function ()
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52876034%2fpass-a-template-template-argument-without-specifying-the-concrete-type%23new-answer', 'question_page');

                                          );

                                          Post as a guest













































































                                          Comments

                                          Popular posts from this blog

                                          What does second last employer means? [closed]

                                          Installing NextGIS Connect into QGIS 3?

                                          One-line joke