奇怪的成员函数指针语法

4

我知道如何声明函数的类型:

typedef void (typedef_void_f)(); // typedef_void_f is void()
using alias_void_f     = void(); // alias_void_f is void()

而且它可以用来声明函数指针:

void function() { std::cout << __PRETTY_FUNCTION__ << '\n'; }

typedef_void_f *a = function; // pointer to void()
alias_void_f   *b = function; // pointer to void()

对于成员函数指针,语法稍微复杂一些:
struct S { void function() { std::cout << __PRETTY_FUNCTION__ << '\n'; } };

typedef void (S::*typedef_void_m_f)();
using  alias_void_m_f = void (S::*)();

typedef_void_m_f c = &S::function; // pointer to S void() member function
alias_void_m_f   d = &S::function; // pointer to S void() member function

这是我对C++中函数指针的理解,我认为这已经足够了。
但在p0172r0技术论文中,我发现了一种我不熟悉的语法:
struct host {
   int function() const;
};

template <typename TYPE>
constexpr bool test(TYPE host::*) { // <---- What is this??
    return is_same_v<TYPE, int() const>;
}

constexpr auto member = &host::function;

test(member);

据我理解这段代码,test函数分离了函数类型和所属对象类型,因此在模板test函数中,TYPE模板参数应该是void(),但如果我尝试以下操作:
void my_test(void() S::*) {}

my_test(&S::function);

我得到了一堆语法错误:

error: variable or field 'my_test' declared void
 void my_test(void() S::*) {}
                   ^
error: expected ')' before 'S'
 void my_test(void() S::*) {}
                     ^
error: 'my_test' was not declared in this scope
     my_test(&S::function);
很明显我不理解p0172r0的test函数语法。有人能解释一下template <typename TYPE> constexpr bool test(TYPE host::*)语法的细节吗?

不,我不是在问模板参数中的 T::* 是什么意思。 - PaperBirdMaster
抱歉,没有及时重新打开它。 - NathanOliver
1
这不仅限于成员指针。如果你有 using T = int(),那么 T* p 是有效的,而 int()* p 被语法规则禁止。 - cpplearner
@cpplearner 是的,正如我所说的那样,在p0172r0文件中已经指出了。 - PaperBirdMaster
2个回答

3

TYPE host::*是一个指向类成员的指针。TYPE是类成员的类型,host::*表示host的成员指针。因此,TYPE host::*接受指向host任何成员的指针。


为什么 void my_test(void() S::*) 不接受 S 中任何 void() 成员的指针? - PaperBirdMaster
据我所知,指向类数据成员和指向类成员函数的指针是两个不同的东西。在我看过的任何代码中,我从未见过您尝试使用的语法。 - NathanOliver
我已经在Wandbox上使用gcc 6.0.0测试了p0172r0的代码。 - PaperBirdMaster
@PaperBirdMaster 这很有趣。我稍后会深入研究一下。 - NathanOliver
NathanOliver,你有机会看一下这个吗? - PaperBirdMaster
显示剩余2条评论

1
尝试使用这个替代方案:
constexpr void my_test(void (S::*)()) {}

那是声明指向返回void且无参数的S成员函数类型的参数的正确方式。

http://ideone.com/EqfYmb


所以,如果 my_test(void (S::*)()) 是声明指向 void() 成员 S 的正确方式,那么 template <typename TYPE> constexpr bool test(TYPE host::*) 不应该是 template <typename TYPE> constexpr bool test(TYPE (host::*)()) 吗?我不理解 p0172r0 上的语法。 - PaperBirdMaster
@PaperBirdMaster 我认为你所说的“拆分”类型是可能的,因为有模板推导规则的存在。 - imreal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接