仅替换成员函数的模板语法
Template syntax to substitute only member functions
我试图创建一个函数重载,因此它只绑定(适用于)一个成员函数。我看了一下 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;
}
函数(或 class 方法)比 return 类型更重要。
函数有参数。每个参数都有一个类型。函数参数的类型是函数签名的一部分。这包括参数为零的函数。
如果您希望模板函数绑定到任意 class 的成员函数,模板函数也必须显式绑定到 class 成员函数的参数类型。这是 C++ 类型安全的一个基本方面:
template<class Ret,
class T,
class ...Args>
void mem_fn(Ret (T::*pm)(Args...))
{
}
class foo {
public:
void bar(int);
};
void foo()
{
mem_fn(&foo::bar);
}
如果您只对绑定到不带参数的成员函数感兴趣,您可以放弃可变参数模板参数,并且您必须相应地显式绑定模板:
template<class Ret,
class T>
void mem_fn(Ret (T::*pm)())
{
}
class foo {
public:
void bar();
};
void foo()
{
mem_fn(&foo::bar);
}
请注意,此模板将仅绑定到不带参数的 class 成员函数。例如,它不会绑定到 void bar(int)
成员函数。
你可以用 std::invoke
涵盖这两种情况:
template <typename F, typename... A>
auto call_me(F func, A... args) { // lambda version
return std::invoke(func, mContainer, args...);
}
对于一个函数对象,比如你的闭包,this 调用 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)...);
}
我试图创建一个函数重载,因此它只绑定(适用于)一个成员函数。我看了一下 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;
}
函数(或 class 方法)比 return 类型更重要。
函数有参数。每个参数都有一个类型。函数参数的类型是函数签名的一部分。这包括参数为零的函数。
如果您希望模板函数绑定到任意 class 的成员函数,模板函数也必须显式绑定到 class 成员函数的参数类型。这是 C++ 类型安全的一个基本方面:
template<class Ret,
class T,
class ...Args>
void mem_fn(Ret (T::*pm)(Args...))
{
}
class foo {
public:
void bar(int);
};
void foo()
{
mem_fn(&foo::bar);
}
如果您只对绑定到不带参数的成员函数感兴趣,您可以放弃可变参数模板参数,并且您必须相应地显式绑定模板:
template<class Ret,
class T>
void mem_fn(Ret (T::*pm)())
{
}
class foo {
public:
void bar();
};
void foo()
{
mem_fn(&foo::bar);
}
请注意,此模板将仅绑定到不带参数的 class 成员函数。例如,它不会绑定到 void bar(int)
成员函数。
你可以用 std::invoke
涵盖这两种情况:
template <typename F, typename... A>
auto call_me(F func, A... args) { // lambda version
return std::invoke(func, mContainer, args...);
}
对于一个函数对象,比如你的闭包,this 调用 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)...);
}