c++ - 仅替换成员函数的模板语法

标签 c++ templates sfinae pointer-to-member

我试图创建一个函数重载,因此它只绑定(bind)(适用于)一个成员函数。我看了一下 std::mem_fn 的函数签名 http://en.cppreference.com/w/cpp/utility/functional/mem_fn

template <class Ret, class T>
/* unspecified */ mem_fn (Ret T::* pm);

所以我这样构造我的参数

template <typename R, typename F>
auto call_me(R C::* func) {
    return (mContainer.*func);
}

但是,我得到了这个错误

.\template.cpp: In function 'int main()':
.\template.cpp:29:49: error: no matching function for call to 'MyClass<int, std::vector<int> >::call_me(std::vector<int>::size_type (std::vector<int>::*)() const noexcept)'
     cout << test.call_me(&std::vector<int>::size) << endl;
                                                 ^
.\template.cpp:16:10: note: candidate: template<class R, class F> auto MyClass<T, C>::call_me(R C::*) [with R = R; F = F; T = int; C = std::vector<int>]
     auto call_me(R C::* func) {
          ^~~~~~~
.\template.cpp:16:10: note:   template argument deduction/substitution failed:
.\template.cpp:29:49: note:   couldn't deduce template parameter 'F'
     cout << test.call_me(&std::vector<int>::size) << endl;

我尝试这样做的原因是,我可以有一个适用于一般 lambda 和函数对象的重载,以及另一个适用于成员函数指针的重载。这是我要实现的目标的一个最小示例。我知道这个问题有点令人困惑,所以如果需要,请随时要求澄清。

#include <vector>
#include <iostream>

using namespace std;

template <typename T, typename C>
struct MyClass {
    // This doesnt work because of SFINAE

    template <typename F, typename... A>
    auto call_me(F func, A... args) { // lambda version
        return func(args...);
    }

    template <typename R, typename F>
    auto call_me(R C::* func) { // member function version
        return (mContainer.*func);
    }

    C mContainer; // this is private in my actual code

};


int main() {
    MyClass<int, std::vector<int> > test;;

    // these two calls will call the member function version of the overload
    cout << test.call_me(&std::vector<int>::size) << endl;

    using insert_func_t = std::vector<int>::iterator(std::vector<int>::*)(std::vector<int>::const_iterator, const int&);
    test.call_me(static_cast<insert_func_t>(&std::vector<int>::insert), test.mContainer.begin(), 4);

    // this call will call the lambda version of the overload
    cout << test.call_me([](std::vector<int>& in){ in.push_back(5); });

    return 0;
}

最佳答案

您可以使用 std::invoke 涵盖这两种情况:

template <typename F, typename... A>
auto call_me(F func, A... args) { // lambda version
    return std::invoke(func, mContainer, args...);
}

对于一个函数对象,比如你的闭包,这会调用operator()。对于成员函数,它将要使用的对象作为参数的前缀,然后使用适当的语法调用它。换句话说,您的工作已经完成。

您还可以考虑完美转发:

template <typename F, typename... A>
auto call_me(F&& func, A&&... args) { // lambda version
    return std::invoke(std::forward<F>(func), mContainer, std::forward<A>(args)...);
}

关于c++ - 仅替换成员函数的模板语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46761837/

相关文章:

wpf - 项目更改时如何触发 cellTemplateSelector

c++ - 内置数组大小的类型是多少?

c++ - 检测算子 +

c++ - 如何制作多人 Flash 游戏?那里有哪些套接字库/我如何制作自己的套接字库?

c++ - 如何让预处理器在宏扩展结果中插入换行符?

c++ - 为什么必须在哪里放置 “template”和 “typename”关键字?

C++,我可以禁止特定的策略组合吗?

c++ - 为什么 sqlite3pp 样本会这样?

c++ - 检查类型是否被声明为元类型系统(对于 SFINAE)

c++ - 强制先尝试一个过载,然后再返回另一个