2015-09-11 78 views
0

我想獲得三個不同的功能,像這樣的呼叫:C++超載靜態常量字符串VS字符數組

foo("aa"); 

像這樣的人,因爲這樣的電話

char buf[2]; 
foo(buf); 

和一個多種變異之一:

const char *ptr; 
//set ptr 
foo(ptr);//don't know buffer size at compile time 

我試試這個:

//and foo1 for pointers, but how??? 

template<size_t N> 
void foo1(char (&)[N], std::false_type) 
{ 
    std::printf("not const\n"); 
} 

template<size_t N> 
void foo1(const char (&)[N], std::true_type) 
{ 
    std::printf("const\n"); 
} 

template<typename arr_t> 
void foo(arr_t arr) 
{ 
    foo1(std::forward<arr_t>(arr), std::is_const<typename std::remove_reference<arr_t>::type>{}); 
} 

foo("a"); 

但它無法編譯,看起來像「一」轉換爲 const char *const char (&)[2]

,但有趣的是,這樣的代碼編譯好:

template<size_t N> 
void f(const char (&)[N]) 
{ 
} 

f("aaaa"); 

所以我怎麼能常數之間重載函數在編譯時(在編譯時知道這個常量的大小)和已知大小的數組,但不是const?

+1

爲什麼不你只是使用數組引用版本?那麼你將得到指針版本的編譯失敗。這不是你所追求的嗎?或者你特別想要運行時失敗。 –

+0

'「aa」'類型爲'const char *'。你如何期望與'const char * ptr'區分開來? – dbush

+4

@dbush,no,''aa「'是一個'const char [3]' –

回答

-1

的問題是,此功能由值取它的參數:

template<typename arr_t> 
void foo(arr_t arr) 

無法通過值陣列,它們衰變到指針,所以,當你具有已知長度以與陣列稱之爲它實例foo<const char*>(const char*)foo<char*>(char*)(取決於數組的常量)並且丟失長度。

你只是想:

template<size_t N> 
void foo(const char (&)[N]) 
{ 
    std::printf("const array\n"); 
} 

template<size_t N> 
void foo(char (&)[N]) 
{ 
    std::printf("non-const array\n"); 
} 

void foo(const char*) 
{ 
    std::printf("not an array\n"); 
} 
+1

這不是我想要的,因爲foo1(「aa」)打印「不是數組」,而我想要「const數組」。從「aa」到const char(&)[3]的對話,參見我的「f」示例。 – user1244932

+0

@ user1244932:所以不要有'const char *'過載...?我根本沒有解決問題。如果你想要一個引用數組的函數,就寫下來。你爲什麼介紹其他功能? –

+1

我想區分兩種變體:(a)編譯器在編譯時有關於char數組長度的知識,(b)編譯器在編譯時沒有關於長度的知識。在變體(a)中,我想爲const數組引入兩個重載,另一個不是const。在變體(b)中,我只想捕捉這些變體。 – user1244932

3

這裏有兩個問題。首先,你的調度功能正在通過價值來論證它的論點。要做到完美的轉發,你應該通過轉發引用來引用你的論點。

第二個問題令我感到驚訝的是pointer decay takes priority over a deduced template,所以一個採用指針的函數將優先於一個採用數組的模板來調用。

您可以使用std::is_array類型特徵標記調度。

template<size_t N> 
void foo1(char (&)[N], std::true_type) 
{ 
    std::cout << "array\n"; 
} 

template<size_t N> 
void foo1(const char (&)[N], std::true_type) 
{ 
    std::printf("const array\n"); 
} 

void foo1(const char*, std::false_type) 
{ 
    std::cout << "pointer\n"; 
} 

template<typename T> 
void foo(T&& x) 
{ 
    foo1(std::forward<T>(x), std::is_array< typename std::remove_reference<T>::type >()); 
} 

Live demo.

+0

只要參數未被聲明爲使得函數將按值取數組,模板就毫不費力地從字符串文字中推導數組類型。即,參數必須是參考類型。 OP的代碼工作得很好,沒有變化,除了修正他試圖完善的參數類型 - 前進。 – bames53

+0

@ bames53不,[OP的代碼將無法正常工作](http://melpon.org/wandbox/permlink/c9mPjn3xw552BMGW),即使你修復了完美的前鋒。至少不是因爲他們要求做的事情。 –

+0

[這裏是](http://coliru.stacked-crooked.com/a/156509d34dcf85fc)OP的代碼,帶有正確的完美轉發,並且支持'char const *'的重載請求。 – bames53

1

所以我怎麼可以重載在編譯時間常數之間的函數(知道這個常量在編譯時的大小)和數組與已知的大小,而不是const的?

隨着一個變化,你的代碼是完全正確的,並且正是你想要的。問題是,你沒有做正確完美轉發:

template<typename arr_t> 
void foo(arr_t arr) 
{ 
    foo1(std::forward<arr_t>(arr), std::is_const<typename std::remove_reference<arr_t>::type>{}); 

完美轉發需要使用轉發參考的:

template<typename arr_t> 
void foo(arr_t &&arr) 
{ 
    foo1(std::forward<arr_t>(arr), std::is_const<typename std::remove_reference<arr_t>::type>{}); 

現在,當你傳遞一個字符串字面arr_t將演繹到const char (&)[N],並且適當的foo1函數將被調用。

當然const也被推斷,並且不需要第二個參數foo1()

和一個多種變異像這樣一個電話:

該附加匹配char const *過載,但其中規定的隱式轉換,使其比char const (&)較差的匹配。

Live


但是如果你只是想這三種類型之間的超載,你不需要亂用完美轉發位都:

template<size_t N> 
void foo(char (&)[N]) 
{ 
    std::printf("not const[]\n"); 
} 

template<size_t N> 
void foo(const char (&)[N]) 
{ 
    std::printf("const[]\n"); 
} 

template<typename T> 
struct dumb_ptr { T *p; dumb_ptr(T *p_) : p(p_) {} }; 

void foo(dumb_ptr<char const>) { 
    std::printf("ptr\n");  
} 

int main() { 

foo("a");   // prints const [] 

char aa[] = "aa"; 
foo(aa);   // prints non const [] 

char const *aaa; 
foo(aaa);   // prints ptr 

char *aaaa; 
foo(aaaa);   // prints ptr 

} 
+0

但是OP想區分第三種類型,const char * ptr;'。 –

+0

@ChrisDrew OPs'foo'可以像const char *一樣工作。我在示例中添加了一個超載來顯示它正在工作。 – bames53

+0

@ChrisDrew [Here's](http://coliru.stacked-crooked.com/a/156509d34dcf85fc)這個例子是OPs'true_type' /'false_type'剩下的東西。 – bames53