2016-04-27 2 views
7

Рассмотрит следующие типы:перегрузки с ЬурейиМ выдает ошибку

#include <iostream> 

typedef unsigned long long  usize_t; 
typedef unsigned __int16  uword_t; 
typedef uword_t     clockval_t;  // time without seconds in format HHMM 

std::string toString(clockval_t nClock) 
{ 
    return std::to_string((usize_t)nClock/100) + ":" + std::to_string((usize_t)nClock % 100); 
} 

std::string toString(uword_t nValue) 
{ 
    return std::to_string((usize_t)nValue); 
} 

void test(void) 
{ 
    uword_t val = 1; 
    clockval_t time = 1023; // 10:23 

    std::cout << "Value: " << toString(val); 
    std::cout << "time: " << toString(time); 
} 

Теперь, когда я пытаюсь скомпилировать это я получаю сообщение об ошибке от компилятора говорил мне, что std::string toString(clockval_t) уже есть тело. Я понимаю, почему это происходит, конечно, потому что typedef - это просто псевдоним для uword_t.

AFAIK единственные решения должны обеспечить отдельный метод:

std::string toClockString(clockval_t); 

или сделать его объект:

class clockval ... 

Правильно ли это или есть какой-то другой способ сделать компилятор выбрать правильная перегрузка?

+0

Ах, радости системы типа C! – Sean

+2

Да, это ИМО немного слабее, потому что весь смысл typedefs заключается в создании новых типов, поэтому компилятор должен иметь возможность правильно различать их, чтобы сделать его последовательным. Тем не менее, я думаю, что есть некоторые проблемы обратной совместимости. – Devolus

ответ

2

Даже если бы был способ заставить компилятор выбрать правильную версию, понимаете ли вы, как это было бы подвержено ошибкам? К счастью, такого способа нет, потому что typedef создает псевдоним и ничего больше.

Предлагаю вам преобразовать его в класс. Если вы обеспечить надлежащий конструктор и оператор преобразования, то вы даже не нужно менять части коды, которые делают использование clockval_t:

class clockval_t { 
public: 
    clockval_t(uword_t aValue) : value(aValue) {} 
    operator uword_t() const { return value; } 

private: 
    uword_t value; 
}; 

... 

clockval_t time = 1023; // works fine 
std::cout << time << std::endl; // works fine 
std::cout << (time/10) << std::endl; // works fine 
+0

СПАСИБО! Это, безусловно, лучший ответ.:) Я проверил машинный код, чтобы убедиться, что нет лишних накладных расходов, а не простого слова (которое было бы моей главной проблемой для объекта), и это ведет себя точно так же, как «слово», имея преимущества типа , :) – Devolus

+0

У этого есть недостаток, что вы теряете все арифметические операции на clockval_t. Вам нужно будет переопределить каждый оператор в классе (если необходимо). –

0

Смысл ЬурейеГо определен в стандарте как (7.1.3 ЬурейеГо спецификатора):

В рамках своей декларации, а-имя ЬурейеГо синтаксический эквивалентно ключевое слово и имена типа связанный с идентификатором (...). Таким образом, typedef-name является синонимом другого типа. В typedef-name не вводится новый тип (...).

Поэтому две функции действительно неоднозначны в отношении типа входного параметра. Вам нужно различать тип (например, используя другой тип, например класс или перечисление), или, возможно, добавить второй параметр (возможно, со значением по умолчанию), указывающий, какой тип типа точно передается.

Ссылка на оригинал ответа : https://softwareengineering.stackexchange.com/questions/254473/in-which-stage-of-compilation-is-typedef-resolved-by-the-compiler

+0

Мне нравится этот ответ из-за цитаты, но я согласен с принятым ответом, что добавление фальшивого параметра - не очень хорошая идея и по существу очень похоже на создание определенного имени функции. – Devolus

1

Правильно ли это или есть какой-либо другой способ заставить компилятор выбрать правильную перегрузку?

Да, вы правы, вы не можете перегружать typedef, поскольку это просто псевдоним. Как вы по праву можете предложить, переименуйте функцию или создайте новый тип с помощью class. Добавление fake параметр просто изменить подпись функции, как правило, плохая идея, переименование более понятно.

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