如何将宏生成的#foo 字符串传递到模板化的 class 中?

How to pass a macro-generated #foo string into a templated class?

我有一个宏:

#define BIND(c_slot, cxx_target)  c_slot = & Generate< 
                                                  decltype(c_slot) 
                                                  , decltype(&cxx_target)
                                                  , &cxx_target 
                                            >::call;

我会这样使用它:

BIND( table->fooslot , Base::foofunc );

Generate 看起来像这样:

template<typename Fc, typename Target, Target target>
struct Generate;

template <  typename R      , typename ...Arg       ,
            typename RTarg  , typename ...TargArg   ,
                                           RTarg(ExtObjBase_noTemplate::*target)(TargArg...) >
struct Generate< R(*)(PyObject*, Arg...),  RTarg(ExtObjBase_noTemplate::*      )(TargArg...),  target >
{
    static R call( PyObject* self, Arg... carg)
    {
        std::cout << "SLOT!" << std::endl;
        try
        {
            RTarg r_cxx = (cxxbase_for(self)->*target) (Convert<Arg>::to_cxx(carg) ...);
            return Convert<RTarg>::to_c(r_cxx);
        }
        catch (...)
        {
            :
        }
    }
};

我想改进 std::cout 以便它输出 WHICH 插槽。

类似于:

#define BIND(c_slot, cxx_target)  c_slot = & Generate< 
                                                  decltype(c_slot) 
                                                  , decltype(&cxx_target)
                                                  , &cxx_target
                                                  , #c_slot
                                            >::call;

但我不知道如何让它发挥作用。

有办法吗?

编辑:一种可能的方法是:

static std::map<void*, std::string> names_map;

:

#define BIND(c_slot, cxx_target)  \
    c_slot = & Generate< decltype(c_slot) ,decltype(&cxx_target), &cxx_target >::call; \
    names_map[offset_of(&cxx_target)] = std::string(#c_slot);

:

template <  STUFF >
struct Generate< STUFF >
{
    static R call( STUFF )
    {
        COUT( "SLOT: " << names_map[offset_of(???)] );

...有什么办法让它起作用吗?

编辑:已解决

您可以这样做:

// Sequence of char
template <char...Cs> struct char_sequence
{
    template <char C> using push_back = char_sequence<Cs..., C>;
};

// Remove all chars from char_sequence from '[=10=]'
template <typename, char...> struct strip_sequence;

template <char...Cs>
struct strip_sequence<char_sequence<>, Cs...>
{
    using type = char_sequence<Cs...>;
};

template <char...Cs, char...Cs2>
struct strip_sequence<char_sequence<'[=10=]', Cs...>, Cs2...>
{
    using type = char_sequence<Cs2...>;
};

template <char...Cs, char C, char...Cs2>
struct strip_sequence<char_sequence<C, Cs...>, Cs2...>
{
    using type = typename strip_sequence<char_sequence<Cs...>, Cs2..., C>::type;
};

// helper to get the i_th character (`[=10=]` for out of bound)
template <std::size_t I, std::size_t N>
constexpr char at(const char (&a)[N]) { return I < N ? a[I] : '[=10=]'; }

// helper to check if the c-string will not be truncated
template <std::size_t max_size, std::size_t N>
constexpr bool check_size(const char (&)[N])
{
    static_assert(N <= max_size, "string too long");
    return N <= max_size;
}

// Helper macros to build char_sequence from c-string
#define PUSH_BACK_8(S, I) \
    ::push_back<at<(I) + 0>(S)>::push_back<at<(I) + 1>(S)> \
    ::push_back<at<(I) + 2>(S)>::push_back<at<(I) + 3>(S)> \
    ::push_back<at<(I) + 4>(S)>::push_back<at<(I) + 5>(S)> \
    ::push_back<at<(I) + 6>(S)>::push_back<at<(I) + 7>(S)>

#define PUSH_BACK_32(S, I) \
        PUSH_BACK_8(S, (I) + 0) PUSH_BACK_8(S, (I) + 8) \
        PUSH_BACK_8(S, (I) + 16) PUSH_BACK_8(S, (I) + 24)

#define PUSH_BACK_128(S, I) \
    PUSH_BACK_32(S, (I) + 0) PUSH_BACK_32(S, (I) + 32) \
    PUSH_BACK_32(S, (I) + 64) PUSH_BACK_32(S, (I) + 96)

// Macro to create char_sequence from c-string (limited to 128 chars)
#define MAKE_CHAR_SEQUENCE(S) \
    strip_sequence<char_sequence<> \
    PUSH_BACK_128(S, 0) \
    >::type::template push_back<check_size<128>(S) ? '[=10=]' : '[=10=]'>

您的代码变为:

template<typename Fc, typename Target, Target target, typename CharSeq>
struct Generate;

template <  typename R      , typename ...Arg       ,
            typename RTarg  , typename ...TargArg   ,
            RTarg(ExtObjBase_noTemplate::*target)(TargArg...) ,
            char...Cs>
struct Generate< R(*)(PyObject*, Arg...),  RTarg(ExtObjBase_noTemplate::*      )(TargArg...),  target , char_sequance<Cs...>>
{
    static R call( PyObject* self, Arg... carg)
    {
        const char name[] = {Cs...};
        std::cout << name << std::endl;
        try
        {
            RTarg r_cxx = (cxxbase_for(self)->*target) (Convert<Arg>::to_cxx(carg) ...);
            return Convert<RTarg>::to_c(r_cxx);
        }
        catch (...)
        {

        }
    }
};

#define BIND(c_slot, cxx_target)  c_slot = & Generate< 
                                              decltype(c_slot) 
                                              , decltype(&cxx_target)
                                              , &cxx_target,
                                              MAKE_CHAR_SEQUENCE(#c_slot)
                                        >::call;