如何使用两个模板参数重载类方法,以便我可以将 std::function 用作其中之一?

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

提问人:Jr_vv 提问时间:11/23/2022 最后编辑:Jr_vv 更新时间:11/23/2022 访问量:58

问:

我需要一些有关使用模板的帮助。 我有这样的代码, 它是包含两个 std::function 对象向量的类,以及一个在其中一个中推送某些函数(bind、lambda 或 functor)的方法:

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;

例如,我希望这段代码将带有两个参数的 lambda 推送到调用方法,如下所示:m_binaryOperationsm_unaryOperationsRegisterOperator

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

但它给了我一个功能式的投射错误。 据我了解,这是因为在一个函数中以两种不同的方式进行解释。class T

如何修改代码以使用模板参数 1 或 2 调用方法,以便知道参数是什么类型以及必须将参数中的向量函数推送到什么?argsCountclass T

我尝试了不同的方法来解决这个问题。

第一个是在类中重载模板,如下所示:

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);
}

但是调试告诉我,它甚至不会进入我上面写的示例的重载函数。

第二个是重载类中的模板,如下所示:

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);
}

我认为默认模板允许我在调用方法时只在模板中定义,但它会导致很多错误。argsCount

希望得到你的帮助。

C++ 模板 STL 重载 std-function

评论

0赞 Caleth 11/23/2022
如果你有一个 C++20 编译器,你可以做并避免拥有if constexpr(requires(){ m_unaryOperations.push_back(fn); }size_t argsCount

答:

2赞 Daniel Langr 11/23/2022 #1

首先,你在这里有一个错别字:

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

它应该是:

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

其次,即使那样它也不会编译,因为对于“普通”,两个分支都需要可编译。如果您有可用的 C++17,则可以解决问题:ifif constexpr

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

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

现场演示:https://godbolt.org/z/bbqs7Knbd

评论

0赞 Jr_vv 11/24/2022
多谢!!它有效。但是带有覆盖模板的代码版本呢,为什么它不起作用?
0赞 Daniel Langr 11/25/2022
@Jr_vv 这不是超载(也不是超载),而是专业化。AFAIK,则不能在类范围内专用化成员函数模板。有关详细信息,请参阅 stackoverflow.com/q/51767514/580083