2

I have a member funtion like this:

class Foo
{
public:
  template<typename... Args>
  static void bar(const Args&... args)
  {
    /* code */
  }
};

And I want to pass it as a template parameter to a member function like this:

class Example
{
public:
  template<typename... Args, typename T> // <- ???
  void doStuff(const Args&... args)
  {
    T(args...);
  }
};

I have tried multiple things here already, but the one that seemed the most promising was this:

class Example
{
public:
  template<typename... Args, typename C, void (C::*F)(Args&...)>
  void doStuff(const Args&... args)
  {
    (C::F)(args...);
  }
};

Whilst troubleshooting I thought maybe it's because I got the function signature of bar wrong, so I changed the template of doStuff to this:

template<typename... Args, typename C, void (C::*F)(const Args&...)>

Which didn't seem to help.

I suspect it is because I don't define, the template of parameter F, but I don't know how to add that. Or maybe I could get around this all together by passing a lambda as an attribute to doStuff. I didn't try that yet though, and would idealy not want to have to resort to that.

EDIT 2:

Here is a minimum reproducable example:

class Foo
{
public:
  template<typename... Args>
  static void bar(const Args&... args)
  {
    /* code */
  }
};

class Example
{
public:
  template<typename... Args, typename C, void (C::*F)(Args&...)>
  void doStuff(const Args&... args)
  {
    (C::F)(args...);
  }
};

class SomeClass
{
public:
  Example ex {};

  template<typename... Args>
  void someFunc(const Args&... args)
  {
    ex.doStuff<Args..., Foo, &Foo::bar>(args...);
  }
};

int main()
{
  SomeClass sc {};
  sc.someFunc("Some ", "Arguments ", "Here");
  return 0;
}

I know, I know, I rushed the question sry

14
  • 2
    Why don't you want do use a lambda? It is the idiomatic solution and much simpler than passing member function pointers. (And also just as fast if that's what you are worried about) Commented Apr 22, 2023 at 14:44
  • 1
    please post a minimal reproducible example. I mean its all there but you must have the code where you try to instantiate the template somewhere, an answer will have to include it too, so why not include it in the question... Commented Apr 22, 2023 at 14:45
  • @463035818_is_not_a_number I also realized I forgot a entry point and instantiation of the template in the post and updated it Commented Apr 22, 2023 at 14:48
  • now I am a little confused. You tried different ways to write the template, but you didnt actually try to instantiate them? I mean that sc.someFunc("Some ", "Arguments ", "Here"); doesnt work is not related to how you write the template Commented Apr 22, 2023 at 14:49
  • 1
    Please provide a minimal reproducible example. Commented Apr 22, 2023 at 14:52

3 Answers 3

2

We don't have to use the (Classtype::*)() syntax with static member function. Static member functions are treated as ordinary free functions. Below is the working example where I've shown how to achieve what you want:

class Foo
{
public:
  template<typename... Args>
  static void bar(const Args&... args)
  {
    /* code */ 
  }
};

class Example
{
public:
  
 
    template< typename... Param,typename Ret, typename... Args>  
    //no need to use any class type here as we have static member function which is treated as ordinary free function
    void doStuff(Ret (*ptrFunc)(const Param&... param),const Args&... args)

    {

    }
};

class SomeThing
{
public:
  Example ex {};

  template<typename... Args>
  void someFunc(const Args&... args)
  {
    ex.doStuff(&Foo::bar<Args...>,args...);    
  }
};

int main()
{
  SomeThing sc {};
  sc.someFunc("Some ", "Arguments ", "Here"); 
  
  return 0;

}
Sign up to request clarification or add additional context in comments.

Comments

0

Many things are unclear. For example, why would you want to pass a template along with arguments that you will use to instantiate it, rather than directly passing the instantiation. However, I suppose this is due to simplification and what you want is to have a static member template as argument of another template.

To my knowledge, this is not possible. At least not directly.

What you can do is use a template template argument to pass a type. A static method of that template can forward to the static method of Foo:

#include <iostream>

class Foo
{
public:
  template<typename... Args>
  static void bar(const Args&... args)
  {
  }
};

template <typename ...Args>
struct helper {
    static void bar(const Args&...args){
        Foo::bar(args...);
    }
};


template<template<typename...> typename M,typename...Args>
void doStuff(const Args&... args) {
    M<Args...>::bar(args...);
}


int main() {
    doStuff<helper,int>(42);
}

Depending on what you actually need, helper could be parametrized on a type so you could use it also for other types that have a bar static mehtod. However, for other types that have a static method of different name we are back to square one, you would need another helper.

If you just want to pass a callable to doStuff perhaps it does not have to be more complicated than this:

 template <typename F, typename Args...>
 void doStuff(F f,const Args&...args) { F(args...); }
 // (no perfect forwarding as in your code and in the code above)

 int main() { 
      doStuff([](int a) { Foo::bar(a); },42);
 }

Comments

0

Unfortunately I don't have too much time but here is a quick shot on how to pass a member function pointer into a function template to select a "callback" to process the data.

#include <iostream>
#include <utility>

struct A
{
    template<class ... Q>
    void x(Q&&... q)    
    {
        std::cout << "A::x\n";
    }
    template<class ... R>
    void y(R&&... r)    
    {
        std::cout << "A::y\n";
    }
    template<class F, class ... W>
    void do_stuff(F&& f, W&&... w)  
    {
        std::cout << "A::do_stuff\n";
        (this->*f)(std::forward<W>(w)...);
    }
};

class B
{
public:

  A a{};

  template<typename... Args>
  void bar(Args&&... args)
  {
    a.do_stuff(&A::x<Args...>, std::forward<Args>(args)...);
    a.do_stuff(&A::y<Args...>, std::forward<Args>(args)...);
  }
};

int main()
{
  B b{};
  b.bar(1, "yes");
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.