2015-03-31 71 views
1

我在我的類中有一個成員函數_wrapper,它封裝了一些其他函數族的一些公共邏輯。這個包裝函數接受指向正在被包裝的函數和它的參數的指針。候選模板被忽略:參數的推導衝突類型:<const T &> vs <T &>

包裝在我班上的實現方式類似於它是如何在這個例子中類Foo完成:

#include <functional> 

class Foo 
{ 
public: 
    void bar1(int a) 
    { 
     /// No-op. 
    } 

    void bar1(int a, int b) 
    { 
     /// No-op. 
    } 

    void bar2(const int & a) 
    { 
     /// No-op. 
    } 

    void foo(int x) 
    { 
     _wrapper_bar1(x);   /// No problems to deduce type 
     _wrapper_bar2(x);   /// No problems to deduce type 

     _wrapper(&Foo::bar1, x); /// Deduction fails 
     _wrapper(&Foo::bar2, x); /// Deduction fails 
    } 

private: 
    template <typename ...Args> 
    void _wrapper(void (Foo::*method) (Args ...), Args && ...args) 
    { 
     /// Do some common stuff here... 

     (this->*method)(std::forward<Args>(args)...); 
    } 

    template <typename ...Args> 
    void _wrapper_bar1(Args && ...args) 
    { 
     bar1(std::forward<Args>(args)...); 
    } 

    template <typename ...Args> 
    void _wrapper_bar2(Args && ...args) 
    { 
     bar2(std::forward<Args>(args)...); 
    } 
}; 

int main(int argc, char ** argv) 
{ 
    Foo().foo(123); 
    return 0; 
} 

當我傳遞一個lvaluefoo的說法int x,到包裝,clang編譯器的投訴,有是衝突和扣除失敗:

test.cpp:21:9: error: no matching member function for call to '_wrapper' 
     _wrapper(&Foo::bar1, x); /// Deduction fails 
     ^~~~~~~~ 
test.cpp:27:10: note: candidate template ignored: deduced conflicting types for parameter 'Args' (<int> vs. <int &>) 
    void _wrapper(void (Foo::*method) (Args ...), Args && ...args) 
     ^
test.cpp:22:9: error: no matching member function for call to '_wrapper' 
     _wrapper(&Foo::bar2, x); /// Deduction fails 
     ^~~~~~~~ 
test.cpp:27:10: note: candidate template ignored: deduced conflicting types for parameter 'Args' (<const int &> vs. <int &>) 
    void _wrapper(void (Foo::*method) (Args ...), Args && ...args) 

事情是我不明白爲什麼會發生這種情況。單獨通過lvalue是可以的,因爲它使用_wrapper_bar1_wrapper_bar2完成。這樣做不會引起任何衝突,即const T &T &

我知道一個解決此錯誤的方法:使用std::move(x)lvalue轉換爲rvalue,但顯然它不是一個修復方法,因爲移動實際上不是必需的。此外,有時我需要在調用包裝函數後使用x,並且使用移動的值是UB。

可能我的模板非常壞,我錯過了一些明顯的事情。我會很感激你的幫助。

編輯:重載Foo::bar1()

+0

在'模板<類型名...參數數量>空隙_wrapper(無效(美孚:: *方法)(參數數量。 ..),Args && ... args)'注意第二個Args強制右值引用... – Jarod42 2015-03-31 11:30:22

+0

@ Jarod42,好吧,它實際上是* universal reference *,它不強制右值。 – GreenScape 2015-03-31 11:33:01

+0

我的意思是它在成員函數指針,並在正常參數。你可能想要'template void _wrapper(void(Foo :: * method)(Args ...),Arg2s && ... args)' – Jarod42 2015-03-31 11:43:41

回答

5

template <typename ...Args> 
void _wrapper(void (Foo::*method) (Args ...), Args && ...args) 

Args可以從2處推導出來。

您可能解決通過引入其它模板參數:

template <typename ...Args, typename ...Arg2s> 
void _wrapper(void (Foo::*method) (Args ...), Arg2s&& ...args) 
{ 
    /// Do some common stuff here... 

    (this->*method)(std::forward<Arg2s>(args)...); 
} 

Live example

+0

你甚至可以做' template void _wrapper(Method method,Args && ... args) { (this - > * method)(std :: forward (args)...); }' – coyotte508 2015-03-31 11:53:02

+0

不幸的是,如果'bar *'過載,此解決方案不起作用。我應該更新我的答案並添加重載版本嗎? – GreenScape 2015-03-31 11:59:20

+0

如果'bar'被重載,那麼'(Foo :: * method)(Args ...)'不明確。所以你必須指定你想要的一個('_wrapper(static_cast &Foo :: bar1,x);')或強制'參數...'處於不可抵扣上下文(並且是正確的類型)。 – Jarod42 2015-03-31 12:05:40

相關問題