簡體   English   中英

泛型成員函數指針作為模板參數

[英]generic member function pointer as a template parameter

考慮這個代碼:

#include <iostream>
using namespace std;

class hello{
public:
    void f(){
        cout<<"f"<<endl;
    }
    virtual void ff(){
        cout<<"ff"<<endl;
    }
};

#define call_mem_fn(object, ptr)  ((object).*(ptr))

template<R (C::*ptr_to_mem)(Args...)> void proxycall(C& obj){
    cout<<"hello"<<endl;
    call_mem_fn(obj, ptr_to_mem)();
}

int main(){
    hello obj;
    proxycall<&hello::f>(obj);
}

當然,這不會在第 16 行編譯,因為編譯器不知道RCArgs是什么。 但是還有另一個問題:如果試圖在ptr_to_mem之前定義這些模板參數,他會遇到這種糟糕的情況:

template<typename R, typename C, typename... Args, R (C::*ptr_to_mem)(Args...)> 
                             //  ^variadic template, but not as last parameter!
void proxycall(C& obj){
    cout<<"hello"<<endl;
    call_mem_fn(obj, ptr_to_mem)();
}

int main(){
    hello obj;
    proxycall<void, hello, &hello::f>(obj);
}

令人驚訝的是,g++ 並沒有抱怨Args不是模板列表中的最后一個參數,但無論如何它無法將proxycall綁定到正確的模板函數,只是指出它是一個可能的候選者。

有什么解決辦法嗎? 我最后的手段是將成員函數指針作為參數傳遞,但如果我可以將它作為模板參數傳遞,它會更適合我的其余代碼。

編輯:正如一些人指出的那樣,這個例子似乎毫無意義,因為 proxycall 不會傳遞任何參數。 這在我正在處理的實際代碼中並非如此:參數是通過 Lua 堆棧中的一些模板技巧獲取的。 但是那部分代碼與問題無關,而且相當冗長,所以我不會在這里粘貼。

你可以嘗試這樣的事情:

template <typename T, typename R, typename ...Args>
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args)
{
    return (obj.*mf)(std::forward<Args>(args)...);
}

用法: proxycall(obj, &hello::f);

或者,要將 PTMF 變成模板參數,請嘗試特化:

template <typename T, T> struct proxy;

template <typename T, typename R, typename ...Args, R (T::*mf)(Args...)>
struct proxy<R (T::*)(Args...), mf>
{
    static R call(T & obj, Args &&... args)
    {
        return (obj.*mf)(std::forward<Args>(args)...);
    }
};

用法:

hello obj;

proxy<void(hello::*)(), &hello::f>::call(obj);

// or

typedef proxy<void(hello::*)(), &hello::f> hello_proxy;
hello_proxy::call(obj);

在現代 C++ 中,可以使用template<auto>和通用 lambda 包裝器:

#include <utility>
#include <functional>

template<auto mf, typename T>
auto make_proxy(T && obj)
{
    return [&obj] (auto &&... args) { return (std::forward<T>(obj).*mf)(std::forward<decltype(args)>(args)...); };
}

struct R {};
struct A {};
struct B {};

struct Foo
{
    R f(A &&, const B &) { return {}; }
    //R f(A &&, const B &) const { return {}; }
};

int main()
{
    Foo foo;
    make_proxy<&Foo::f>(foo)(A{}, B{});
    //make_proxy<static_cast<R (Foo::*)(A &&, const B &) const>(&Foo::f)>(std::as_const(foo))(A{}, B{});
    //make_proxy<static_cast<R (Foo::*)(A &&, const B &)>(&Foo::f)>(foo)(A{}, B{});
}

如果有重載,應該像在注釋代碼中一樣顯式指定成員函數類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM