指向成员变量方法的指针作为模板参数

问题描述 投票:0回答:1

使用C++17,我需要修改下面的

struct Bind
来处理具有任意参数的方法。方法的返回值始终为
void
。目标是在 constexpr 上下文中创建函数指针,该指针可用于稍后在非 constexpr 上下文中创建
std::functions

https://godbolt.org/z/q4M1KxqPh

#include <functional>

template <typename Owner, typename Owned, Owned Owner::* Member, void(Owned::* Method)(int)>
struct Bind {
    static auto apply(Owner* owner) {
        return std::function<void(int)>( [=](int x) { ((owner->*Member).*Method)(x); } ); 
    }
};

struct Foo {
    void x(int x) { }
    void y(float y, int x) { }
};

struct Bar {
    Foo foo1;
    Foo foo2;
};

int main() {
    Bar bar;

    std::function<void(int)> (*bindX)(Bar* owner) = &Bind<Bar, Foo, &Bar::foo1, &Foo::x>::apply;
    std::function<void(int)> targetX = bindX(&bar);
    targetX(42);


    std::function<void(float, int)> (*bindY)(Bar* owner) = &Bind<Bar, Foo, &Bar::foo2, &Foo::y>::apply;
    std::function<void(float, int)> targetY = bindY(&bar);
    targetY(3.14f, 42);
}

error: could not convert template argument '&Foo::y' from 'void (Foo::*)(float, int)' to 'void (Foo::*)(int)'

上面演示了两个示例参数列表。但是,Bind 需要处理具有在编译时固定的任意参数的函数签名。

这个问题看起来需要类似的东西

template <typename Owner, typename Owned, Owned Owner::* Member, typename ...Args, void(Owned::* Method)(Args...)>
struct Bind {
    static auto apply(Owner* owner) {
        return std::function<void(int)>( [=](Args&&... args) { 
            ((owner->*Member).*Method)(std::forward<Args>(args)...); 
        }); 
    }
};

但是,这行不通,因为

error: parameter pack 'Args' must be at the end of the template parameter list

或者,也许

template <typename Owner, typename Owned, Owned Owner::* Member, template<typename ...Args> void(Owned::* Method)(Args...)>
struct Bind {
    static auto apply(Owner* owner) {
        return std::function<void(int)>( [=](Args&&... args) { 
            ((owner->*Member).*Method)(std::forward<Args>(args)...); 
        }); 
    }
};

但是,这也无法解析。

expected 'class' or 'typename' before 'void'

有“模板化模板非类型参数”这样的东西吗?

这看起来也对

template <auto Method>
很有用。但是,我不知道如何使 lambda 签名起作用......

c++ variadic-templates
1个回答
0
投票

灵感来自https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0127r1.html

我设法通过模板部分专业化解决了这个问题。 https://godbolt.org/z/7doP5563e

#include <functional>

template <typename Owner, typename Owned, Owned Owner::* Member, typename Method, Method method>
struct Bind;

template <typename Owner, typename Owned, Owned Owner::* Member, typename... Args, void(Owned::* method)(Args...)>
struct Bind<Owner, Owned, Member, void(Owned::*)(Args...), method> {
    static auto apply(Owner* owner) {
        return std::function<void(Args...)>( [=](Args&&... args) { 
            ((owner->*Member).*method)(std::forward<Args>(args)...); 
        }); 
    }
};

struct Foo {
    void x(int x) { }
    void y(float y, int x) { }
};

struct Bar {
    Foo foo1;
    Foo foo2;
};

int main() {
    Bar bar;

    std::function<void(int)> (*bindX)(Bar* owner) = &Bind<Bar, Foo, &Bar::foo1, decltype(&Foo::x), &Foo::x>::apply;
    std::function<void(int)> targetX = bindX(&bar);
    targetX(42);


    std::function<void(float, int)> (*bindY)(Bar* owner) = &Bind<Bar, Foo, &Bar::foo2, decltype(&Foo::y), &Foo::y>::apply;
    std::function<void(float, int)> targetY = bindY(&bar);
    targetY(3.14f, 42);
}

© www.soinside.com 2019 - 2024. All rights reserved.