2013-05-16 84 views
1

我不太確定如何提出這個問題,因爲我關於模板使用的知識很淺,但這裏什麼也沒有。模板成員函數和非模板重載的參數推導

我有一個類,我想爲所有數值提供一個函數模板,然後這個函數模板調用期望std :: string的非模板版本,如下所示。

template< class T > void 
add_to_header(const std::string &key, const T &val) 
{ 
    add_to_header(key, std::to_string(val)); 
} 

virtual void 
add_to_header(const header& header); 

virtual void 
add_to_header(const std::string &key, const std::string &val); 

此代碼編譯乾淨,但我失去了做一個爲const char []一個呼叫的能力。

instance.add_to_header("Example1", 4); // successful 
instance.add_to_header("Example2", std::string("str val")); // successful 
instance.add_to_header("Example3", "Not fun"); // error - none of the 9 overloads could convert all the argument types 

解決此問題的慣用方法是什麼?

回答

7

如果您在add_to_header聲明,它需要能夠調用其參數,然後在模板超載將通過SFINAE被淘汰to_string註明:

void add_to_header(const std::string &key, const std::string &val); 

template<typename T> auto add_to_header(const std::string &key, const T &val) 
-> decltype(std::to_string(val), void()) // uses comma operator 
{ 
    add_to_header(key, std::to_string(val)); 
} 

注意,非模板超負荷需求在模板主體定義的語法點處可見,以便正文內的調用可以看到非模板重載。

使用C++ 14度的限制,我們可以更換typename T(或class T)與封裝的要求約束:

template<typename T> constexpr bool ToStringable() { 
    using namespace std; 
    void to_string(...); 
    return is_same<string, decltype(to_string(declval<T>()))>::value; 
} 

template<ToStringable T> 
void add_to_header(const std::string &key, const T &val) 
{ 
    add_to_header(key, std::to_string(val)); 
} 
+0

「*非模板重載需要在模板主體定義的語法點可見*」=>這可能是您的答案中最重要的部分。 GCC 4.7甚至不會編譯OP的示例1和2,除非聲明被正確地重新排序。 +1 – syam

+2

現在,這是一個聰明的技巧 - 使用尾隨函數類型和逗號運算符來施加概念約束。尼斯。 –

+0

這真的很酷!謝謝。 – flumpb

0

爲什麼你要使用的模板?你可以簡單地重載add_to_header函數......

+0

重載所有數字類型?隨時給我模板,謝謝。 – Gorpik