2016-04-24 3 views
0

Я озадачен, почему компилятор (g ++ ver 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

Спасибо @corykramer, он работает. Интересно, почему компилятор не может сменить 'long' на' std :: size_t' автоматически. – packetie

+0

Он * может * изменять эти типы, но, как @Barry упоминает ниже, ни один из них не * лучше *, чем другой, поэтому функция неоднозначна. – CoryKramer

ответ

3

Аргументы в этом вызове:

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

имеют тип {const char[3], size_t}. У нас есть три жизнеспособных кандидатов перегрузки для этого набора аргументов:

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

В каждом случае size_t может быть преобразован ко второму типу аргументов с помощью интегрального преобразования (size_t к bool или size_t к long) или с плавающим интегралом конверсия (size_t - double). Ни одно из этих преобразований не лучше другого - все они имеют одинаковый ранг: Конверсия. Следовательно, нет лучших жизнеспособным кандидатом, потому что мы не можем различать три варианта.

Одним из источников путаницы может быть то, что long «ближе» к size_t, чем bool есть. Но это не имеет значения с точки зрения рейтинга конверсии. Они оба связаны с интегральной конверсией, и нет никакой дифференциации между различными типами интегральных преобразований .

Для устранения неоднозначности, либо:

  • обеспечивает новую перегрузку: addField(const char*, size_t)
  • бросил второй аргумент, чтобы быть типа вы хотите - x.addField("hi", static_cast<long>(s.size()))
  • коллапс всех перегруженный в шаблон функции: template <class T> void addField(const char*, T)

Возможно, вам понадобится последний.


Там является дифференциация между интегральной продвижения (например, char к int) и интегрального преобразования хотя (например, к intchar). Продвижение - лучшее преобразование, чем конверсия.

+0

Спасибо @Barry. Я добавил метод 'void addField (const char * fieldName, std :: size_t value);' и который позаботился об ошибке компиляции с помощью 's.size()', однако он дал похожие ошибки, когда я пытаюсь сделать: 'x.addField (" hi ", 123);'. Я знаю, что 'static_cast ' может помочь, но это заставит главную функцию выглядеть уродливой. Интересно, есть ли элегантный подход? – packetie

+0

@codingFun Такая же проблема - неоднозначное преобразование. Вероятно, вы должны создать 'addField' шаблон функции. – Barry

+0

Спасибо @barry за хорошее предложение. Я добавил отдельную функцию для int и для std :: size_t в исходном фрагменте кода, и он сработал. – packetie

Смежные вопросы