Специализация шаблона по категории значения указателя на функцию-член - PullRequest
0 голосов
/ 09 октября 2018

Я хочу передать тип указателя на функцию-член в шаблон класса, чтобы шаблон мог использовать пакет параметров для работы с типами параметров функции.В качестве примера я хотел бы вычислить сумму размеров типов параметров для функции-члена.Чтобы это работало со всеми категориями значений, мне нужно было предоставить 24 (я забыл что-нибудь?) Специализации для разных типов указателей на функции:

#include <iostream>

struct X {
    void foo (char) {}
    void cfoo (short) const {}
    void vfoo (short, char) volatile {}
    void cvfoo (int) const volatile {}

    void lfoo (int, char) & {}
    void clfoo (int, short) const & {}
    void rfoo (int, short, char) && {}
    void crfoo (int, int) const && {}

    void vlfoo (int, int, char) volatile & {}
    void cvlfoo (int, int, short) const volatile & {}
    void vrfoo (int, int, short, char) volatile && {}

    void cvrfoo (int, int, int) const volatile && {}

    void vafoo (char, ...) {}
    void vacfoo (short, ...) const {}
    void vavfoo (short, char, ...) volatile {}
    void vacvfoo (int, ...) const volatile {}

    void valfoo (int, char, ...) & {}
    void vaclfoo (int, short, ...) const & {}
    void varfoo (int, short, char, ...) && {}
    void vacrfoo (int, int, ...) const && {}

    void vavlfoo (int, int, char, ...) volatile & {}
    void vacvlfoo (int, int, short, ...) const volatile & {}
    void vavrfoo (int, int, short, char, ...) volatile && {}

    void vacvrfoo (int, int, int, ...) const volatile && {}
};

template <typename TPtr, TPtr Ptr>
struct ArgsSize;

#define DEF_ArgSize_SPEC(qual)      template <typename R, typename C, typename... Args, R (C::*fPtr) (Args...) qual> \
                                    struct ArgsSize<R (C::*) (Args...) qual, fPtr> { \
                                        static constexpr std::size_t value = (0 + ... + sizeof(Args)); \
                                    }; \
                                    template <typename R, typename C, typename... Args, R (C::*fPtr) (Args..., ...) qual> \
                                    struct ArgsSize<R (C::*) (Args..., ...) qual, fPtr> { \
                                        static constexpr std::size_t value = 1000 + (0 + ... + sizeof(Args));  /* For testing, add a big number to denote variadic arguments */  \
                                    };

DEF_ArgSize_SPEC(&)
DEF_ArgSize_SPEC(const &)
DEF_ArgSize_SPEC(&&)
DEF_ArgSize_SPEC(const &&)

DEF_ArgSize_SPEC(volatile &)
DEF_ArgSize_SPEC(const volatile &)
DEF_ArgSize_SPEC(volatile &&)

DEF_ArgSize_SPEC(const volatile &&)


DEF_ArgSize_SPEC()
DEF_ArgSize_SPEC(const)
DEF_ArgSize_SPEC(volatile)
DEF_ArgSize_SPEC(const volatile)

template <auto Ptr>
void test () {
    std::cout << ArgsSize<decltype(Ptr), Ptr>::value << std::endl;
}

int main () {
    test <&X::foo> ();
    test <&X::cfoo> ();
    test <&X::vfoo> ();
    test <&X::cvfoo> ();

    test <&X::lfoo> ();
    test <&X::clfoo> ();
    test <&X::rfoo> ();
    test <&X::crfoo> ();

    test <&X::vlfoo> ();
    test <&X::cvlfoo> ();
    test <&X::vrfoo> ();

    test <&X::cvrfoo> ();

    test <&X::vafoo> ();
    test <&X::vacfoo> ();
    test <&X::vavfoo> ();
    test <&X::vacvfoo> ();

    test <&X::valfoo> ();
    test <&X::vaclfoo> ();
    test <&X::varfoo> ();
    test <&X::vacrfoo> ();

    test <&X::vavlfoo> ();
    test <&X::vacvlfoo> ();
    test <&X::vavrfoo> ();

    test <&X::vacvrfoo> ();
}

Я использовал макрос, потому что даже для этого тривиального примера:есть много дублирования.Внутри «ArgsSize» я работаю с типом результата (R), классом (C) и типами параметров (Args ...).Есть ли лучший / более короткий способ сделать это?

...