Подтвердить что ты не робот

Указатель на функции: что означает `R (* C:: *) (Args...)` означает?

Рассмотрим следующий код:

template <class>
struct test: std::integral_constant<int, 0> {};
template<class R, class C, class... Args>
struct test<R(C::*)(Args...)>: std::integral_constant<int, 1> {};
template<class R, class C, class... Args>
struct test<R(*C::*)(Args...)>: std::integral_constant<int, 2> {};
template<class R, class C, class... Args>
struct test<R(**C::*)(Args...)>: std::integral_constant<int, 3> {};
template<class R, class C, class... Args>
struct test<R(C::**)(Args...)>: std::integral_constant<int, 4> {};
template<class R, class C, class... Args>
struct test<R(C::***)(Args...)>: std::integral_constant<int, 5> {};

Я совершенно не знаю, что означают (*C::*), (**C::*), (C::**) и (C::***). Я хотел бы привести пример test<decltype(f)>, чей value будет равен 2, 3, 4 и 5. Плюс, в этом случае, как синтаксис для f, который вызовет функцию-член?

4b9b3361

Ответ 1

Рассмотрим этот пример:

struct s {
    void test1();
    void(*test2)();
    void(**test3)();
};

int main() {
    static_assert(test<decltype(&s::test1)>::value == 1);   
    static_assert(test<decltype(&s::test2)>::value == 2);   
    static_assert(test<decltype(&s::test3)>::value == 3);   

    auto test4 = &s::test1;
    static_assert(test<decltype(&test4)>::value == 4);   

    auto test5 = &test4;
    static_assert(test<decltype(&test5)>::value == 5);   
}

Вот типы:

R(C::*)(Args...) - указатель на функцию-член.
R(*C::*)(Args...) - указатель на элемент данных, который является указателем на функцию.
R(**C::*)(Args...) - указатель на элемент данных, который является указателем на указатель функции.
R(C::**)(Args...) - указатель на указатель на функцию-член.
R(C::***)(Args...) - указатель на указатель на указатель на функцию-член.

Чтобы вызвать их, рассмотрите слегка измененный пример:

struct s {
    void test1() {std::cout << "test1\n";}
    void(*test2)() = [] {std::cout << "test2\n";};

    void(*test3Helper)() = [] {std::cout << "test3\n";};
    void(**test3)() = &test3Helper;

    void test4() {std::cout << "test4\n";}
    void test5() {std::cout << "test5\n";}
};

int main() {
    s obj;  

    auto test4 = &s::test4;

    auto test5Helper = &s::test5;
    auto test5 = &test5Helper;  

    (obj.*(&s::test1))();
    (*(obj.*(&s::test2)))(); // note that the dereference is unnecessary
    (**(obj.*(&s::test3)))(); // note that the second dereference is unnecessary
    (obj.**(&test4))();
    (obj.***(&test5))();
}

Обратите внимание, что в каждом случае, если у вас есть переменная со значением соответствующего &[s::]testN, вы можете заменить (&[s::]testN) на эту переменную. Также обратите внимание, что для test2 и test3 я разыменован до тех пор, пока функция не вернется, а не указатель функции для иллюстрации.