Home > Net >  How to overload class method with two template parameters, so I can use std::function as one of them
How to overload class method with two template parameters, so I can use std::function as one of them

Time:11-25

I need some help with working with templates. I have code like this, it's class holding two vectors of std::function object, and a method that pushes some function (bind, lambda, or functor) in one of them:

typedef std::function<int(int)> unFuncPtr;
typedef std::function<int(int, int)> binFuncPtr;

class Operations
{
public:
    template <size_t argsCount, class T>
    void RegisterOperator(T fn) {
        if (argsCount == 1) {
            m_unaryOperations.push_back(fn);
        }
        if (argsCount == 2) {
            m_binaryOperations.push_back(fn);
        }
    }

private:
    std::vector<unFuncPtr> m_binaryOperations;
    std::vector<binFuncPtr> m_unaryOperations;

I wanted this code to push, for example, lambda with two argements in m_binaryOperations or lambda with only one argument to m_unaryOperations calling method RegisterOperator like this:

Operations operations;
operations.RegisterOperator<1>([](int x) {return x * x; })
operations.RegisterOperator<2>([](int x, int y) {return x   y; })

But it gives me a funtion-style-cast error. As I understand it's because of interpreting class T in two different ways in one function.

How can I modify the code to call the method with template parameter 1 or 2 for argsCount, so it will be known what type is class T and to what vector function from the argument must be pushed?

I tried different ways to solve this problem.

The first one is to overload templates inside the class like this:

template <size_t argsCount, class T>
void RegisterOperator(T fn) {
}

template<>
void RegisterOperator<1>(unFunPtr fn) {
    m_unaryOperations.push_back(fn);
}

template<>
void RegisterOperator<2>(binFunPtr fn) {
    m_binaryOperations.push_back(fn);
}

But debugging showed me that it won't even go inside overloaded functions with the examples I wrote upper in question.

The second one is to overload templates inside the class like this:

template<class T = unFunPtr>
void RegisterOperator<1>(T fn) {
    m_unaryOperations.push_back(fn);
}

template<class T = binFunPtr>
void RegisterOperator<2>(T fn) {
    m_binaryOperations.push_back(fn);
}

I thought the default template lets me define only argsCount in the template when I'm calling the method, but it causes a lot of errors.

Hoping for your help.

CodePudding user response:

First, you have a typo here:

std::vector<unFuncPtr> m_binaryOperations;
std::vector<binFuncPtr> m_unaryOperations;

It should be:

std::vector<unFuncPtr> m_unaryOperations;
std::vector<binFuncPtr> m_binaryOperations;

Second, even then it wouldn't compile, since with "ordinary" if, both branches needs to be compilable. You can resolve the problem with if constexpr if you have C 17 available:

void RegisterOperator(T fn) {
  if constexpr (argsCount == 1) 
    m_unaryOperations.push_back(fn);

  if constexpr (argsCount == 2) 
    m_binaryOperations.push_back(fn);
}

Live demo: https://godbolt.org/z/bbqs7Knbd

  • Related