2011-07-24 203 views
4

我正在學習/學習模板功能專業化規則。我開始使用此功能模板專業化幫助

template<typename T> 
std::string toString(const T& t) 
{ 
    ostringstream out; 
    out << t; 
    return out.str(); 
} 

現在,我想專門它爲const char *

typedef const char* ccharPtr; 

template<> 
std::string toString(const ccharPtr& s) 
{ 
    cout << "in specialization" << endl; // just to let me know 
    return std::string(s); 
} 

我想要做的,沒有一個typedef,但到目前爲止,我想不通出來。

該特化適用於const char *,但不適用於char *。

const char* s1 = "Hi" 
cout << toString(s1); // works 
char s2[] = "There"; 
cout << toString(s2); // doesn't work, since s2 isn't const char* 
cout << toString(", Bob"); // doesn't work. Why not? 

我想單個專業化爲每個案件工作,但無法解決它。

回答

1

我認爲這應該工作:

template <typename T> 
    std::string to_string(const T &) 
{ 
    ... 
} 

// non templated 
std::string to_string(const char* x) 
{ 
    ... 
} 
+0

是的,它會工作取代strcpy,但我想學習模板特殊化。我知道這是一種人爲的情況。 – John

+1

所以我想你可能不得不專門爲const char *和char *一次。由於char *不是const char *,我猜C++不符合專業化,並使用更通用的功能。如果你想讓const char *和char *都使用相同的特化,我想你必須明確地將你的參數從char *轉換爲const char *。 – neodelphi

+0

@John:你應該學習模板專業化的第一件事情之一是函數模板專業化很少有幫助。 – aschepler

6

爲什麼專門化?只是超載功能。完全專業化的功能模板通常不是必需的。

template <typename T> 
std::string toString(const T& in) 
{ 
    ostringstream out; 
    out << in; 
    return out.str(); 
} 

std::string toString(char const* in) 
{ 
    return in; 
} 

OK,如果你真的要做到這一點,那麼你必須考慮到字符串文字—的類型,雖然他們含蓄轉換char const* —是char const[N]

template <typename T> 
std::string toString(T const & t) { 
    ostringstream out; 
    out << t; 
    return out.str(); 
} 

template <> 
std::string toString(char const* const & s) { 
    cout << "(S1)"; 
    return std::string(s); 
} 

template <size_t N> 
std::string toString(char (&s)[N]) { 
    cout << "(S2)"; 
    return std::string(s); 
} 

template <size_t N> 
std::string toString(char const (&s)[N]) { 
    cout << "(S3)"; 
    return std::string(s); 
} 

int main() { 
    const char* s1 = "Hi"; 
    cout << toString(s1) << endl; 
    char s2[] = "There"; 
    cout << toString(s2) << endl; 
    cout << toString(", Bob") << endl; 
} 

// Output: 
// (S1)Hi 
// (S2)There 
// (S3), Bob 

Live demo.

可以省略專業化S2,然後雙方"There"", Bob"將使用S3

被警告,實際上,這根本不是專業化的。我寧願通過創建新的函數模板來作弊。但我必須得到size_t參數;你只能做真正專業化這裏如果你N拿起一個價值,把它寫進函數簽名作爲具體類型的一部分,或者如果你能部分專門的函數模板。

+0

但是如果我想要呢? – John

+0

傳遞一個字符串文字,然後它推導出一個數組類型,它不匹配指針類型(這是專門化,因此類型必須完全匹配)。隨着你顯示的重載,它將使用第二個'toString',因爲轉換序列是不明確的,但第二個是非模板,因此獲勝。 –

+0

@John:看我的編輯。 –

6

它不起作用的原因是因爲它實際上不是正確的類型。字符串文字不是const char*類型,它們的類型是const char[N]。當你傳遞一個字符串時,T被推斷爲char[N]。這是完全匹配,專業化不是。你不能規定字符串文字,因爲這需要部分規範,而C++不支持部分功能專業化。

1

我在Sun Studio C++編譯器中遇到類似的問題。首先,我使用了兩個數組過載(有或沒有constchar (&)[N])和兩個指針過載(char*const char*)。

令我驚訝的是,如toString("quoted literal")這樣的調用被使用,似乎不可能強制編譯器選擇數組過載。更有趣的是 - 對於像char lit[] = "literal",toString(lit)這樣的參數選擇了數組超載!

經過一番思考,我找到了一種方法,使代碼的行爲作爲部分功能專業化。訣竅就是讓SFINAE

首先使用,定義一個模板從(const) char[N]

template<typename T> 
    struct is_literal { 
}; 

template<size_t N> 
struct is_literal<const char[N]> { 
    typedef std::string type; 
    static const size_t len = N - 1; // subtract terminating null char from N 
}; 

template<size_t N> 
struct is_literal<char[N]> { 
    typedef std::string type; 
    static const size_t len = N - 1; 
}; 

template<> 
struct is_literal<const char*> { 
    typedef std::string ptr_type; 
}; 

template<> 
struct is_literal<char*> { 
    typedef std::string ptr_type; 
}; 

內的typedef type行爲區分(const) char*enable_ifptr_typedisable_if

我們可以使用is_literal實施功能:

template<typename T> 
typename is_literal<T>::type 
toString(T& arg) 
{ 
    std::cout << "(literal)"; 
    // note the second argument which means length 
    // this can be a performance gain because no strlen call is needed 
    return std::string(arg, is_literal<T>::len); 
} 

template<typename T> 
typename is_literal<T>::ptr_type 
toString(T& arg) 
{ 
    std::cout << "(raw pointer)"; 
    return std::string(arg); 
} 

某些編譯器可能有const問題 - 對於那些可能需要重載的const T& arg

我主要利用這款解決方案性能方面的原因,當我有頻繁調用的函數,並要保存strlen來電或簡單memcpy