简体   繁体   English

成员函数指针的类型推导

[英]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 ? ?

General suggestion for type investigations型式调查的一般建议

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的类型,揭示该类型是什么。

is &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 in bar ? bar中的f是什么类型?

if you put如果你把

static_assert(std::is_same_v<void, decltype(f)>);

inside of bar , the compiler will tell youbar里面,编译器会告诉你

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::*)()

How does &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(*)()是一个指向从voidvoid的自由函数的指针,它不同于void (Foo::*)() ,它是一个从voidvoidFoo函数的指针成员

How can I restrict a template to be instatiated only for member functions?如何限制模板仅用于成员函数?

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

And what if I want to restrict the match to member function with a specific signature?如果我想将匹配限制为具有特定签名的成员函数怎么办?

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 . barf的类型是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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM