Как я могу устранить неоднозначность этого кода шаблона? - PullRequest
1 голос
/ 09 мая 2009

У меня проблемы с выяснением, как решить ошибку компилятора, с которой я столкнулся. Я сократил это до этого простейшего представления:

enum EAtomId { EAtomId_Test };

int StringFormat(char* o_dest, size_t i_destSizeChars, const char* i_format, ...);

template <size_t SIZE>
int StringFormat(char (&o_dest)[SIZE], EAtomId i_format, ...);

void func()
{
    char textBuffer[1000];
    StringFormat(textBuffer, EAtomId_Test, "hi there");
}

Ошибка компилятора:

repro.cpp(17) : error C2666: 'StringFormat' : 2 overloads have similar conversions
    C:\Users\sbilas\Desktop\repro.cpp(9): could be 'int StringFormat(char *,size_t,const char *,...)'
    while trying to match the argument list '(char [1000], EAtomId, const char [9])'

Это полная ошибка, кстати. Я немного удивлен, что он не перечисляет обе доступные версии ..

У меня есть пара проблем с этой ошибкой. Во-первых, я не понимаю, почему это неоднозначно. Разве компилятор не должен видеть версию char (&) [] как очевидный случай для сравнения? И второе, как я могу предотвратить преобразование этого перечисления в size_t, когда он выполняет поиск? Похоже, я сталкиваюсь здесь с некоторыми очень специфическими правилами C ++.

Самый простой обходной путь для меня - это поместить size_t для размера буфера перед фактическим буфером. Но это нарушит все наши соглашения, в которых мы помещаем буфер, а затем размер в наш код. Есть ли другой способ сделать это?

Это на VC ++ 2005, кстати, но воспроизводится на паре других моих компиляторов (это в кроссплатформенной игре).

Ответы [ 2 ]

2 голосов
/ 11 мая 2009

Проблема с приведенным выше кодом связана с обычными правилами разрешения перегрузки и не относится к шаблонам. Следующий код с двумя обычными функциями все еще показывает неоднозначность:

enum EAtomId { EAtomId_Test };
const int SIZE=1000;

int StringFormat(char * s
  , size_t i_destSizeChars
  , const char* i_format
  , ...);

int StringFormat(char (&a)[SIZE]
  , EAtomId i_format
  , ...);

void func()
{
    char textBuffer[SIZE];
    StringFormat (textBuffer, EAtomId_Test, "hi there");
}

Применимые правила для разрешения перегрузки работают следующим образом (13.3.3):

  • Для каждого набора аргументов определите набор преобразований, которые имеют место
  • Лучшая функция - это функция, для которой все преобразования не менее хороши, чем преобразования во всех других перегрузках.

Взяв каждый из них по очереди, мы имеем:

Функция 1:

  1. textBuffer-> s: Массив к указателю (точное соответствие 13.3.3.1.1 / 3) - Идентичность
  2. EAtomId_Test-> i_destSizeChars: возможное продвижение и интегральное преобразование
  3. string literal-> const char *: Массив для указателя

Функция 2:

  1. textBuffer-> a: преобразование идентичности
  2. EAtomId_Test-> EAtomId: преобразование удостоверений
  3. строковый литерал-> многоточие: Ellipsis Conversion

Сравнивая каждое из этих преобразований по очереди, вы получаете:

  1. Функция 1 совпадает с функцией 2
  2. Функция 2 лучше, чем Функция 1
  3. Функция 1 лучше, чем Функция 2

Таким образом, ни функция 1, ни функция 2 не менее хороши для всех преобразований, поэтому вызов неоднозначен.

2 голосов
/ 09 мая 2009

У вас есть два объявления для StringFormat:

int StringFormat(char* o_dest, size_t i_destSizeChars,
                 const char* i_format, ...);

template <size_t SIZE>
int StringFormat(char (&o_dest)[SIZE], EAtomId i_format, ...);

Читайте о зависимых от аргументов правилах поиска и подстановки, когда доступен как шаблон функции, так и обычная (не шаблонная) функция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...