[英]Type deduction for a member function pointer
I know there are similar questions on SO, but the usages there seem different to what I have.我知道关于 SO 有类似的问题,但那里的用法似乎与我所拥有的不同。 Here is my MRE:
这是我的 MRE:
#include <iostream>
#include <functional>
using namespace std;
void freeFunction() {}
struct Foo { void memberFunction() {} };
template<typename FunctionPtrT>
void foo(FunctionPtrT* f) { f(); }
template<typename InstanceT, typename FunctionPtrT>
void bar(InstanceT&& i, FunctionPtrT f) { std::mem_fn(f)(i); }
template<typename InstanceT, typename FunctionPtrT>
void baz(InstanceT&& i, FunctionPtrT* f) {}
int main() {
foo(&freeFunction); //Ok, obviously
bar(Foo(), &Foo::memberFunction); //Ok, how?!
// Error: candidate template ignored: could not match 'FunctionPtrT *' against 'void (Foo::*)()'
baz(Foo(), &Foo::memberFunction); //why?!
return 0;
}
Why is &Foo::memberFunction
not resolving to a pointer?为什么
&Foo::memberFunction
不解析为指针? What is the type of f
in bar
? bar
中的f
是什么类型? If it's not a pointer how am I able to pass it to std::mem_fun
that is defined as template< class M, class T > /*unspecified*/ mem_fn(MT::* pm) noexcept;
如果它不是指针,我怎么能将它传递给定义为
template< class M, class T > /*unspecified*/ mem_fn(MT::* pm) noexcept;
的std::mem_fun
? ?
I think the easiest way to answer questions like "what is the type of x
in this context " is to put a static_assert(std::is_same_v<void, delctype(x)>);
我认为回答“在这种情况下
x
的类型是什么”之类的问题的最简单方法是放置一个static_assert(std::is_same_v<void, delctype(x)>);
in that same context.在同样的背景下。 The compiler will then tell you the
static_assert
ion failed because void
is not equal to the type of x
, revealing what that type is.然后编译器会告诉你
static_assert
离子失败,因为void
不等于x
的类型,揭示该类型是什么。
&Foo::memberFunction
a pointer? &Foo::memberFunction
是指针吗? And there are variations of that.并且有一些变化。
For instance, if you truly want to know wheter &Foo::memberFunction
is a pointer, then ask it this way:例如,如果你真的想知道
&Foo::memberFunction
是否是一个指针,那么这样问:
static_assert(std::is_pointer_v<decltype(&Foo::memberFunction)>);
and the compiler will tell you something along the lines of编译器会告诉你一些类似的东西
Static_assert failed due to requirement 'std::is_pointer_v<void (Foo::*)()>' [static_assert_requirement_failed]
so it just can't match against FunctionPtrT*
.所以它不能与
FunctionPtrT*
匹配。
As regards至于
What is the type of
f
inbar
?bar
中的f
是什么类型?
if you put如果你把
static_assert(std::is_same_v<void, decltype(f)>);
inside of bar
, the compiler will tell you在
bar
里面,编译器会告诉你
Static_assert failed due to requirement 'std::is_same_v<void, void (Foo::*)()>'
meaning that the type of f
is void(Foo::*)()
.意味着
f
的类型是void(Foo::*)()
。
&Foo::memberFunction
's type from a free function pointer? &Foo::memberFunction
的类型如何来自自由函数指针? Compare this with the error you get if you define将此与您定义时得到的错误进行比较
void f();
and assert并断言
static_assert(std::is_same_v<void, decltype(f)>);
The compiiler will tell you编译器会告诉你
Static_assert failed due to requirement 'std::is_same_v<void, void (*)()>'
So the point is that void(*)()
, a pointer to a free function from void
to void
, is different from void (Foo::*)()
, a pointer member of Foo
function from void
to void
.所以关键是
void(*)()
是一个指向从void
到void
的自由函数的指针,它不同于void (Foo::*)()
,它是一个从void
到void
的Foo
函数的指针成员。
If you want your template to match only member functions, can go for如果你希望你的模板只匹配成员函数,可以去
template<typename InstanceT, typename R, typename C>
void baz(InstanceT&& i, R C::* f) { }
or, if you want it to match any member function of Foo
, you can clearly either change the order of the template parameters such that you can provide C
manually或者,如果您希望它匹配
Foo
的任何成员函数,您可以清楚地更改模板参数的顺序,以便您可以手动提供C
template<typename C, typename R, typename InstanceT>
void baz(InstanceT&& i, R C::* f) { }
which allows you to call baz<Foo>(/* args */);
它允许您调用
baz<Foo>(/* args */);
, or you can simply hardcode Foo
in place of C
: ,或者您可以简单地硬编码
Foo
代替C
:
template<typename R, typename InstanceT>
void baz(InstanceT&& i, R Foo::* f) { }
As you see, we already have a placeholder R
, for the return type.如您所见,我们已经有一个占位符
R
,用于返回类型。
If we also wanted to have a placeholder for the arguments, we could go for this:如果我们还想为参数设置一个占位符,我们可以这样做:
template<typename R, typename C, typename ...Args>
void baz(R (C::*f)(Args...));
Which will just match the same function as the previous example.这将与前面的示例匹配相同的功能。 I showed this just to make you see that, if you want to type the arguments out, you must put parenthesis around
C::*f
, or just C::*
, if you want to omit the name (the lack of parenthesis is the typo in the comment under your question).我展示这个只是为了让你看到,如果你想输入参数,你必须在
C::*f
周围加上括号,或者只是C::*
,如果你想省略名称(缺少括号是您问题下评论中的错字)。 Therefore, if you want to restrict the match to a specific signature, let's say void()
, this is how you do it:因此,如果您想将匹配限制为特定签名,比如说
void()
,您可以这样做:
template<typename C>
void baz(void (C::*f)());
What is the type of f in bar?
bar中的f是什么类型?
The type of f
in bar
is void (Foo::*)()
ie, a pointer to a member function of class Foo
that has no parameter and has the return type of void
. bar
中f
的类型是void (Foo::*)()
,即指向类Foo
的成员函数的指针,该函数没有参数并且返回类型为void
。
The reason baz(Foo(), &Foo::memberFunction);
原因
baz(Foo(), &Foo::memberFunction);
fails is that &Foo::memberFunction
is a pointer to a member function is distinct from an ordinary pointer to some type .失败在于
&Foo::memberFunction
是一个指向成员函数的指针,它不同于指向某个类型的普通指针。
In fact, member function pointers are not actually pointers .事实上, 成员函数指针实际上并不是指针。 So the argument of type
void (Foo::*)()
cannot be passed to parameter FunctionPtrT* f
.因此
void (Foo::*)()
类型的参数不能传递给参数FunctionPtrT* f
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.