2012-03-15 62 views
3

我想通過刪除接受不關心成員的特殊化(通過enable_if),根據成員的「類型」自動選擇正確的指向成員的指針。未被enable_if排除的不明確的模板參數

我有以下代碼:

class test; 

enum Type 
{ 
    INT_1, 
    FLOAT_1, 
    UINT_1, 
    CHAR_1, 
    BOOL_1, 
    INT_2, 
    FLOAT_2, 
    UINT_2, 
    CHAR_2, 
    BOOL_2 
}; 
template<typename T, Type Et, typename func> struct SetterOk       { static const bool value = false; }; 
template<typename T> struct SetterOk<T,INT_1,void (T::*)(int)>       { static const bool value = true; }; 
template<typename T> struct SetterOk<T,FLOAT_1,void (T::*)(float)>      { static const bool value = true; }; 
template<typename T> struct SetterOk<T,UINT_1,void (T::*)(unsigned int)>    { static const bool value = true; }; 
template<typename T> struct SetterOk<T,CHAR_1,void (T::*)(char)>      { static const bool value = true; }; 
template<typename T> struct SetterOk<T,BOOL_1,void (T::*)(bool)>      { static const bool value = true; }; 
template<typename T> struct SetterOk<T,INT_2,void (T::*)(int,int)>      { static const bool value = true; }; 
template<typename T> struct SetterOk<T,FLOAT_2,void (T::*)(float,float)>    { static const bool value = true; }; 
template<typename T> struct SetterOk<T,UINT_2,void (T::*)(unsigned int, unsigned int)> { static const bool value = true; }; 
template<typename T> struct SetterOk<T,CHAR_2,void (T::*)(char,char)>     { static const bool value = true; }; 
template<typename T> struct SetterOk<T,BOOL_2,void (T::*)(bool,bool)>     { static const bool value = true; }; 

template <bool, class T = void> struct enable_if {}; 
template <class T> struct enable_if<true, T> { typedef T type; }; 


template<typename T, Type Et> 
struct Helper 
{ 
    template<typename U> 
    static void func(U method, typename enable_if<SetterOk<T,Et,U>::value>::type* dummy = 0) 
    { 
    } 
}; 

class test 
{ 
    public: 
     void init() 
     { 
      Helper<test,INT_2>::func(&test::set); 
     } 

     void set2(int); 
     void set(int); 
     void set(int,int); 
     void set(float,float); 
}; 

int main() 
{ 
    test t; 
    t.init(); 
    return 0; 
} 

我期待它來選擇所有可能的正確的函數。問題是編譯器說「不能推導出模板參數,因爲函數參數不明確」。

看來,我不知道如何使用enable_if,因爲如果這樣,編譯器將只允許專門如果指定的函數具有正確的類型......

注意,我想有C++ 03解決方案(如果可能的話) - 我的代碼必須在一些舊的編譯器上編譯。

在此先感謝

+0

編譯器只是簡單地不知道哪個集合重載選擇甚至開始實例化處理 – PlasmaHH 2012-03-15 16:33:45

+0

我想我已經找到了一個替代解決方案來解決你的問題。請檢查我的答案。 – Agentlien 2012-03-15 17:39:31

回答

1

你永遠不能指代一個重載函數沒有消除歧義它(指:static_cast它荷蘭國際集團爲正確的類型)。當你實例化Helper::func時,函數參數的類型在不消除歧義的情況下是無法知道的。

+0

但編譯器可以嘗試專門爲每個重載的'&Helper :: set'函數,然後選擇匹配的(如果存在)。那麼,爲什麼編譯器不能像那樣工作? 是否有解決方法? – Synxis 2012-03-15 16:46:03

+0

@Synxis問題甚至比'SetterOK'的實例更早出現,但是在'Helper'中,由於第二個參數的類型未知,無法實例化。我的錯。沒有真正的解決方法。重載函數在這些上下文中很難使用。 – pmr 2012-03-15 16:52:40

+0

不明白「第二個參數的類型是未知的」:它是INT_2,它是一個枚舉值,如此完全已知,不是嗎? – Synxis 2012-03-15 17:01:53

1

它不編譯的原因很簡單,就是有幾個不同的重載函數,它不知道你指的是哪一個。當然,只有其中一個(void set(int,int))實際編譯,給定Helper<test,INT_2>。但是,編譯器還不夠。

得到這個編譯將是一個辦法,明確投&test::set爲適當的類型:

Helper<test,INT_2>::func(static_cast<void (test::*)(int,int)>(&test::set));

另一種方法是使用顯式模板特:

Helper<test,INT_2>::func<void (test::*)(int,int)>((&test::set));

無論哪種方式,您都需要讓編譯器知道您嘗試引用哪些函數。

編輯:

據我瞭解,你希望能夠推斷,從使用A型,功能類型應使用哪個的。以下替代實現這一點:

template<typename T, Type Et> struct SetterOK{}; 
template<typename T> struct SetterOK<T,INT_1> {typedef void (T::*setter_type)(int);}; 
template<typename T> struct SetterOK<T,FLOAT_1> {typedef void (T::*setter_type) (float);}; 
// ... 
template<typename T> struct SetterOK<T,INT_2> {typedef void (T::*setter_type)(int,int);}; 
// .... 

template<typename T, Type Et> 
struct Helper 
{ 
    template<typename U> 
    static void func(U method) 
    { 
    } 
}; 

class test 
{ 
public: 
    void init() 
    { 
    Helper<test,INT_2>::func<SetterOK<test,INT_2>::setter_type >(&test::set); 
    } 

    void set2(int); 
    void set(int); 
    void set(int,int); 
    void set(float,float); 
}; 

int main() 
{ 
    test t; 
    t.init(); 
    return 0; 
} 

附加編輯:

一個以爲只是發生在我身上。在你做了這種特殊情況下,其中U是SetterOK :: setter_type,事情可以進一步通過對FUNC完全除去模板參數簡化:

static void func(typename SetterOK<T,Et>::setter_type method) 
{ 
} 

這將使init方法更簡單:

void init() 
{ 
    Helper<test,INT_2>::func(&test::set); 
} 
+0

謝謝你的想法,但我已經使用這個。我問這個問題的原因是因爲我有一個SetterOK,它的setter_type爲'void(T :: *)(int)',我希望能夠傳遞像'void(T :: *)(MyEnum )」。棘手的一點是我不知道'MyEnum'存在。但還有更多的:指向成員的指針可能有1,2,3或4個參數... 作爲一個解決方案,我做了4個專門化,它們都需要一個函數'void(T :: *)(。 ...)(其中'...'是'U','U,U','U,U,U'或'U,U,U,U',仍然存在模糊調用的情況,但更少。 – Synxis 2012-03-15 18:37:13

相關問題