2017-06-10 44 views
0

我有以下代碼:禁用測試條件上一個成功

struct has_to_string {}; 
struct has_error_string {}; 

template<typename T> 
struct checker 
{ 
    template<typename, typename> struct checker_helper; 

    template<typename C> 
    static has_to_string test(checker_helper<C, decltype(&C::toString)> *); 
    template<typename C> // Enable this test only if the previous one has failed 
    static has_error_string test(checker_helper<C, decltype(&C::errorString)> *); 
    template<typename C> 
    static std::false_type test(...); 

    using type = decltype(test<T>(nullptr)); 
}; 

template<typename T> 
using checker_t = typename checker<T>::type; 

template<typename T1, typename T2, typename R> 
using enable_if_same = typename std::enable_if<std::is_same<T1, T2>::value, R>::type; 

template<typename T, typename C> 
inline enable_if_same<std::false_type, C, QString> _moduloHelper(const QString & s, const T & value) 
{ return s.arg(value); } 

template<typename T, typename C> 
inline enable_if_same<has_to_string, C, QString> _moduloHelper(const QString & s, const T & value) 
{ return s.arg(value.toString()); } 

template<typename T, typename C> 
inline enable_if_same<has_error_string, C, QString> _moduloHelper(const QString & s, const T & value) 
{ return s.arg(value.errorString()); } 

此代碼可以讓我打電話給一個特定的功能(在這種情況下toStringerrorString)如果模板參數具有此功能。這完美地工作。我所遇到的唯一問題是當我使用這個函數的同時具有errorStringtoString函數的類。

在這種情況下,由於checker::test函數的模糊調用,程序不再編譯。我完全理解爲什麼代碼不能編譯,但如果遇到這種情況,我想每次選擇toString版本,但我不知道該怎麼做。

BTW,這是如何調用_moduloHelper

int main() 
{ 
    QString str("%1"); 
    _moduloHelper<QUrl, checker_t<QUrl>>(str, QUrl()); 
} 

我當然有這個周圍的包裝,但在這裏,這是不是問題的關鍵。

+0

使用兩個不同名稱的函數 - 一個檢查'toString',另一個檢查'errorString'。然後按照您認爲合適的方式進行兩個測試的邏輯組合。 –

回答

1

我會提供我的解決方案,它不像您最初那樣簡約。有時在C++模板中,元編程代碼的增長非常快。但是,我的解決方案除了解決問題外,還有另一個優點 - 它檢查函數的返回類型。您可能會考慮使用預處理器來減少代碼冗餘。

template <typename T> 
struct to_string_checker { 
    template <typename C, 
      typename 
      = typename std::enable_if<std::is_same<decltype(std::declval<C>().toString()), 
                QString>::value, 
             void>::type> 
    static std::true_type test(int*); 
    template <typename C> 
    static std::false_type test(...); 

    constexpr static bool value = decltype(test<T>(nullptr))::value; 
}; 

template <typename T> 
struct to_error_string_checker { 
    template < 
    typename C, 
    typename = typename std:: 
     enable_if<std::is_same<decltype(std::declval<C>().errorString()), QString>::value, 
       void>::type> 
    static std::true_type test(int*); 
    template <typename C> 
    static std::false_type test(...); 

    constexpr static bool value = decltype(test<T>(nullptr))::value; 
}; 

template <typename T> 
typename std::enable_if<to_string_checker<T>::value, QString>::type 
_moduloHelper(const QString& s, const T& value) { 
    return s.arg(value.toString()); 
} 

template <typename T> 
typename std::enable_if<(!to_string_checker<T>::value 
         && to_error_string_checker<T>::value), 
         QString>::type 
_moduloHelper(const QString& s, const T& value) { 
    return s.arg(value.errorString()); 
} 

template <typename T> 
typename std::enable_if<(!to_string_checker<T>::value 
         && !to_error_string_checker<T>::value), 
         QString>::type 
_moduloHelper(const QString& s, const T& value) { 
    return s.arg(value); 
} 

int main() { 
    QString str("%1"); 
    _moduloHelper(str, QUrl()); 
    QString str2("%1"); 
    _moduloHelper(str, 10).toStdString(); 
} 
+0

您的解決方案非常棒,但不適用於應使用_moduloHelper第一個版本的類型(例如'int') – Forbinn

+0

請參閱更新。 – Yuki

+0

好吧,它的作品感謝您的幫助。 – Forbinn