2012-02-27 9 views
2

У меня есть две функции, которые я перегруженные для моего класса отладки:перегруженная функция не используется:

template<class IteratorT> 
    inline debug& 
    operator()(const std::string& name, 
       IteratorT begin, 
       IteratorT end) 
    { 
     _stream << indent(internal) << "g< " << name << " : [ "; 
     for (auto i = begin; i != end; i++) 
     _stream << (*i) << " "; 
     _stream << "] >" << std::endl; 

     return *this; 
    } 

И

inline debug& 
    operator()(const std::string& name, 
      std::vector<uint8_t>::const_iterator begin, 
      std::vector<uint8_t>::const_iterator end) 
    { 
    _stream << indent(internal) << "u8< " << name << " : [ " << std::hex; 
    std::copy(begin, end, std::ostream_iterator<uint32_t>(_stream, " ")); 
    _stream << "] >" << std::endl; 

    return *this; 
    } 

Вот является пропущено, как он используется:

int main() 
{ 
    debug log; 

    std::vector<uint8_t> vec; 
    vec.push_back(0xde); 
    vec.push_back(0xad); 
    vec.push_back(0xc0); 
    vec.push_back(0xde); 

    log("vec", vec.begin(), vec.end()); 
} 

Выход (поскольку он не печатается в виде шестнадцатеричных символов, я пропустил неформатированный результат):

g< "vec" : [ ... ] > 

Вместо

u8< "vec" : [ de ad c0 de ] > 

По какой-то причине компилятор не собирание правильный, перегруженной функции.

$ g++47 --version 
g++47 (GCC) 4.7.0 20120224 (experimental) 

ответ

2

Проблема в коде заключается в том, что разрешение перегрузки учитывает только аргументы функции, а не как результат будет использоваться. Это означает, что выражение vec.begin() (обратно vec.end()) считает, что vec является неконстантным вектором и, таким образом, использует неконстантную версию.

Хотя существует неявное преобразование из std::vector<>::iterator в std::vector<>::const_iterator, это требовало преобразование считает перегрузку как худший кандидат на разрешение, чем функции шаблона с заменой типа является std::vector<>::iterator.

На обходных путях, вы можете перегрузить как для iterator и const_iterator (лучшего решения, так как решение всего вызываемого), или вы можете исправить вызовы, заставляя вектор быть константным с помощью гипса: static_cast<const std::vector<uint8_T>& >(vec).begin() (который является уродливым и требует, чтобы исправление было применено во всех вызовах, которое трудно поддерживать)

+0

Хорошо. С другой стороны, перегрузка лучше, чем частичная специализация? – nerozehl

+0

частичная специализация будет использоваться, если вы хотите особого поведения для всех векторных итераторов по сравнению с общими. Не уверен, возможно ли частично специализироваться на итераторах, значение value_type - uint8_t – CashCow

+0

@nerozehl: Вы не можете частично специализировать функцию, поэтому вопрос имеет ясный простой ответ ... возможный или невозможный.Теперь вы можете перенести функцию как статическую не-шаблонную функцию-член класса шаблона, и в этом случае вы можете частично специализироваться, получая гибкость за счет дополнительного кода. Но я не уверен, что вы многое извлечете из этого. С другой стороны, если вы имеете в виду * полную * специализацию функции, следует предпочесть перегрузки, но я не могу вспомнить точные детали того, почему и где это важно ... google для него :) –

2

К сожалению, ваша специализация не вызывается, потому что вы передаете vector<uint8_t>::iterator не vector<uint8_t>::const_iterator и находит точное совпадение с помощью шаблона.

Чтобы исправить это, вы либо создаете перегруз для инетераторов, не являющихся константами, либо создаете константу-ссылку на свой вектор и вызываете begin()/end().

+0

Не имеет ли 'std :: vector'' const_iterator begin() const; 'который должен быть сопоставлен? – nerozehl

+0

@nerozehl: прочитайте мой ответ, разрешение перегрузки учитывает только аргументы, а не как результат будет использоваться. В этом случае, поскольку вектор не является константой, он будет выбирать 'iterator begin();' как лучший кандидат для вызова 'vec.begin()'. –

1

Это выбор универсальной версии, потому что вы проходите мимо vector<uint8_t>::iterator, а не vector<uint8_t>::const_iterator. Вы должны добавить третий operator(), который принимает версию не const и передает ее на номер const.

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