2013-12-23 61 views
1

我知道,我知道。這個問題似乎被問了好幾次。但所有的答案都不是我想要的,因爲它們在編譯時不能解決整個問題。或者他們沒有在使用C++ 11特性的實際編譯器VS,XCode和GCC(沒有#ifdefs)上工作。或者至少,他們在解釋時失去了我。所以我嘗試了我自己:模板:在編譯時檢查和使用Methode

我試圖實現一種方法,我可以給任何類型。只要使用應該使用的std :: to_string就可以將類型轉換爲std :: string。如果它是一個自寫類的對象,它應該有一個「toString」方法,而不是該方法應該使用的方法。如果這個決定是在編譯期間完成的,那就好了。在這裏,我走了這麼遠:

#include <stdio.h> 
#include <iostream> 
#include <string> 

class Test 
{ 
public: 
    template <typename T> static auto has_toString_method(T& t) -> decltype(t.toString(), bool()) { return true; } 
    static int has_toString_method(...) { return 0; } 

    template< class T> static void toString(T value) 
    { 
     toString(value,has_toString_method(value));  
    } 

    template< class T> static void toString(T value,bool) 
    { 
     value.toString(); 
    } 

    template< class T,bool> static void toString(T value,int) 
    { 
     printf("It works with to_string"); 
    } 
}; 


class MyToStringTest 
{ 
public: 
    void toString() 
    { 
     printf("It works toString");   
    } 
}; 

int main() 
{ 
    MyToStringTest tst; 

    Test::toString(5); // This fails because the compiler tries to resolve the bool arc. 
    Test::toString(tst); 

return 0; 
} 

除此之外,該代碼實際上不是VS2012編譯(我畫的線),這還不算在編譯的時候(我覺得)一個完整的決策。我錯過了什麼?什麼是禁食,最小的方式來得到這個運行?

作爲附加問題。如果有「std :: to_string」失敗並且缺少「toString」來聲明或調用「第三種方式」,是否有可能?

UPDATE:

我得到的錯誤,手忙腳亂我是複製和粘貼的定義,在錯誤的地方,而不是:

template< class T,bool> static void toString(T value,int) 
    { 

我已經(當然)寫的:

template< class T> static void toString(T value,int) 
    { 

比它不僅會編譯,它也會工作!但其他問題將繼續存在。

+0

你必須使用SFINAE,看到http://stackoverflow.com/a/264088/2684539 – Jarod42

回答

1

這工作:

#include <stdio.h> 
#include <cstdint> 
#include <iostream> 
#include <string> 

template<int i> 
struct ToStringMethod { 
    template<typename T> 
    static void toString(T value) { 
    printf("It works with 3rd method\n"); 
    } 
}; 

template<> 
struct ToStringMethod<1> { 
    template<typename T> 
    static void toString(T value) 
    { 
    value.toString(); 
    } 
}; 

template<> 
struct ToStringMethod<2> { 
    template<typename T> 
    static void toString(T value) 
    { 
    printf("It works with to_string\n"); 
    } 
}; 

class Test 
{ 
public: 
    template <typename T> static auto has_string_support(T& t) -> decltype(t.toString(), std::int8_t()) { return true; } 
    template <typename T> static auto has_string_support(T& t) -> decltype(std::to_string(t), std::int16_t()) { return true; } 
    static std::uint32_t has_string_support(...) { return true; } 

    template< class T> static void toString(T value) 
    { 
     ToStringMethod<sizeof(has_string_support(value))>::toString(value);  
    } 

}; 


class MyToStringTest 
{ 
public: 
    void toString() 
    { 
     printf("It works toString\n");  
    } 
}; 

class NoneString {}; 

int main() 
{ 
    MyToStringTest tst; 
    NoneString  none; 

    Test::toString(5); // This fails because the compiler tries to resolve the bool arc. 
    Test::toString(tst); 
    Test::toString(none); 

return 0; 
} 
+0

功能'has_to_string'唐不需要執行,聲明就足夠了。 – Jarod42

1

以下可能會有所幫助:

#include <string> 
#include <type_traits> 

#define HAS_MEM_FUNC(name, Prototype, func)       \ 
    template<typename U>           \ 
    struct name {             \ 
     typedef char yes[1];          \ 
     typedef struct { char dummy[2]; } no;      \ 
     template <typename T, T> struct type_check;     \ 
     template <typename T = U>         \ 
     static yes &chk(type_check<Prototype, &T::func> *);   \ 
     template <typename > static no &chk(...);     \ 
     static bool const value = sizeof(chk<U>(0)) == sizeof(yes); \ 
    } 

HAS_MEM_FUNC(has_to_string, std::string(T::*)() const, toString); 


class Test 
{ 
public: 

    template<typename T> 
    static typename std::enable_if<has_to_string<T>::value, std::string>::type 
    toString(const T& t) { 
     /* something when T has toString ... */ 
     return t.toString(); 
    } 

    template<typename T> 
    static typename std::enable_if<!has_to_string<T>::value, std::string>::type 
    toString(const T& t) { 
     /* something when T doesnt have toString ... */ 
     return std::to_string(t); 
    } 
}; 

class MyToStringTest 
{ 
public: 
    std::string toString() const 
    { 
     return "It works toString"; 
    } 
}; 

int main(int argc, char** argv) 
{ 
    MyToStringTest tst; 

    Test::toString(5); 
    Test::toString(tst); 

    return 0; 
}