2015-05-19 49 views
3

我想創建一個模板,在另一個對象上調用成員函數,該對象返回與成員函數相同的類型。在成員函數上使用decltype的語法有點難看,但它似乎適用於除一個之外的任何情況。如何處理void decltype();

這裏的電話:

struct container: map<string, C> 
{ 
    template< typename MemFnPtrType, typename... _ArgTypes> 
    auto safeOperation(string key, MemFnPtrType mfp, _ArgTypes&&... args) 
     -> decltype((((C*)nullptr)->*mfp)(args...)) 
    { 
     C* pC = NULL; 
     decltype((pC->*mfp)(args...)) result; 

     iterator it = find(key); 
     if (it != end()) 
     { 
      C* pC = &(it->second); 
      result = (pC->*mfp)(args...); 
      cout << "result:" << result << "\n"; 
     } 
     else 
     { 
      cout << "key: " << key << " missing\n"; 
     } 
     return result; 
    } 
}; 

這工作得很好,直到成員函數返回void。

有沒有辦法檢測到這一點,並排除違規行?

我明顯可以創建一個voidSafeOperation函數。我不介意創建另一個模板,但我想使用相同的名稱「safeOperation」,以便呼叫站點不需要根據成員函數的返回類型使用不同的幫助器。

謝謝!

完整的例子: http://cpp.sh/7ft

回答

9

不幸的是,我覺得你有不得不SFINAE返回類型困在這裏。與類型特徵開始(這是方式清潔比你decltype表達)

template <typename MF, typename... Args> 
using Res = typename std::result_of<MF(C, Args...)>::type; 

然後只需切換:

template <typename MF, typename... Args> 
typename std::enable_if< 
    std::is_same<Res<MF, Args...>, void>::value 
>::type safeOperation(string key, MF mfp, Args... args) 
{ 
    /* void case */ 
} 

template <typename MF, typename... Args> 
typename std::enable_if< 
    !std::is_same<Res<MF, Args...>, void>::value, 
    Res<MF, Args...> 
>::type safeOperation(string key, MF mfp, Args... args) 
{ 
    /* non-void case */ 
} 

或者你可以在is_void標記調度:

template <typename MF, typename... Args> 
Res<MF, Args...> safeOperation(string key, MF mfp, Args... args) 
{ 
    return safeOperation(std::is_void<Res<MF, Args...>>{}, 
         key, mfp, args...); 
} 

附:

template <typename MF, typename... Args> 
void safeOperation(std::true_type /* void */, 
        string key, MF mfp, Args... args) 
{ .. } 

template <typename MF, typename... Args> 
Res<MF, Args...> safeOperation(std::false_type /* non-void */, 
           string key, MF mfp, Args... args) 
{ .. } 
+1

或標籤在'is_void'上發送。 –

+0

@ T.C。我通常不是一個巨大的粉絲,但在這種情況下,它很乾淨。 – Barry

+0

我能夠編譯第一個案例,但使用is_void dispatch的!void案例中的結果的語法似乎正在逃避我: http://cpp.sh/7mep – Brad