2016-04-24 25 views
0

我很困惑爲什麼編譯器(g ++版本4.8.4)無法編譯下面的代碼片段。在電話x.addField("hi", s.size());中,我認爲編譯器可以簡單地使用方法void addField(const char *fieldName, long value),因爲它顯然是最好的匹配。g ++有麻煩選擇正確的方法

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

using namespace std; 

class strDum { 
public: 
    void addField(const char *fieldName, const char *fmt, ...); 
    void addField(const char *fieldName, bool value); 
    void addField(const char *fieldName, long value); 
    void addField(const char *fieldName, double value); 
}; 

void strDum::addField(const char *fieldName, const char *fmt, ...) { 
} 
void strDum::addField(const char *fieldName, bool value) { 
} 
void strDum::addField(const char *fieldName, long value) { 
} 
void strDum::addField(const char *fieldName, double value) { 
} 

int main(int argc, char *argv[]) 
{ 
    string s = "hello"; 
    strDum x; 
    x.addField("hi", s.size()); 
    return 0; 
} 

以下是編譯器錯誤消息

$ g++ -std=c++11 te4.cc 
te4.cc: In function ‘int main(int, char**)’: 
te4.cc:29:27: error: call of overloaded ‘addField(const char [3], std::basic_string<char>::size_type)’ is ambiguous 
    x.addField("hi", s.size()); 
         ^
te4.cc:29:27: note: candidates are: 
te4.cc:16:6: note: void strDum::addField(const char*, const char*, ...) <near match> 
void strDum::addField(const char *fieldName, const char *fmt, ...) { 
    ^
te4.cc:16:6: note: no known conversion for argument 2 from ‘std::basic_string<char>::size_type {aka long unsigned int}’ to ‘const char*’ 
te4.cc:18:6: note: void strDum::addField(const char*, bool) 
void strDum::addField(const char *fieldName, bool value) { 
    ^
te4.cc:20:6: note: void strDum::addField(const char*, long int) 
void strDum::addField(const char *fieldName, long value) { 
    ^
te4.cc:22:6: note: void strDum::addField(const char*, double) 
void strDum::addField(const char *fieldName, double value) { 
    ^

任何想法?

+1

實際上,這將簽名'(const char *,std :: size_t)' – CoryKramer

+0

Thanks @corykramer,它的工作原理。我想知道爲什麼編譯器不能自動將'long'更改爲'std :: size_t'。 – packetie

+0

它*可以*更改爲這些類型,但是@Barry在下面提到,它們都不比其他類型更好*,因此該函數不明確。 – CoryKramer

回答

3

在此調用的參數:

x.addField("hi", s.size()); 

有型{const char[3], size_t}。我們爲這個組參數3個可行的過載候選:

void addField(const char*, bool); 
void addField(const char*, long); 
void addField(const char*, double); 

在每種情況下,size_t可以經由積分轉換(size_tboolsize_tlong)被轉換爲第二個參數類型或浮動積分轉換(size_tdouble)。這些轉換中沒有一個比另一個更好 - 它們都具有相同的等級:轉換。因此,不存在可行的候選人,因爲我們無法區分這三種選擇。

混淆的一個來源可能是longbool更「接近」size_t。但從轉換排名的角度來看這並不重要。它們都涉及積分轉換,並且在不同積分轉換類型之間不存在區分。

消除歧義,或者:

  • 提供了一個新的重載:addField(const char*, size_t)
  • 投的第二個參數是你想要的類型 - x.addField("hi", static_cast<long>(s.size()))
  • 崩潰的所有重載成一個函數模板:template <class T> void addField(const char*, T)

也許你會想要最後一個。


一個組成促進(例如charint)和積分轉換雖然(例如intchar)之間的差異。該促銷是一種比轉換更好的轉化。

+0

謝謝@Barry。我添加了一個方法'void addField(const char * fieldName,std :: size_t value);'並且用'size()'處理了編譯錯誤,但是當我嘗試做時它給出了類似的錯誤: 'x.addField(「hi」,123);'。我知道'static_cast '可能會有幫助,但它會使主要功能看起來很醜。不知道是否有一個優雅的方法? – packetie

+0

@codingFun同樣的問題 - 模糊轉換。你應該使'addField'成爲一個函數模板。 – Barry

+0

非常感謝@barry的建議。我在原始代碼片段中爲int和std :: size_t添加了一個單獨的函數,並且它工作正常。 – packetie