2012-02-27 43 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<>::iteratorstd::vector<>::const_iterator的隐式转换,但此必需的转换将过载视为分辨率的最差候选,而不是类型替换为std::vector<>::iterator的模板函数。

作为变通方法,可以重载两个iteratorconst_iterator(最好的解决方案,因为该解决方案是在刚刚被呼叫者),也可以固定通过迫使矢量通过流延的手段为常量的调用:static_cast<const std::vector<uint8_T>& >(vec).begin()(这是丑陋的,并需要修复应用于所有通话,这是很难保持)

+0

好的。在旁注中,超载是否比部分专业化更好? – nerozehl 2012-02-27 17:32:34

+0

如果您希望所有向量迭代器在一般情况下具有特殊行为,将使用部分专用化。不知道是否有可能部分专注于value_type为uint8_t – CashCow 2012-02-27 17:43:43

+0

@nerozehl的迭代器:你不能部分地专门化一个函数,所以这个问题有一个明确的简单答案......可能与不可能。现在,您可以将该函数移动为模板类的静态非模板成员函数,在这种情况下,您可以部分专门化,以额外代码为代价获得灵活性。但我不确定你会从中得到什么。另一方面,如果你的意思是一个*完整的*专业化的功能,过载应该是首选,但我不记得为什么/它在哪里重要的具体细节...谷歌它:) – 2012-02-27 17:44:57

2

不幸的是您的专业不会被调用,因为你逝去的vector<uint8_t>::iteratorvector<uint8_t>::const_iterator,它通过模板找到完全匹配。

要解决这个问题,您可以为非常量迭代器创建一个重载,或者为您的向量创建一个常量引用,并在其上调用begin()/end()

+0

不'std :: vector'有'const_iterator begin()const;'应该匹配? – nerozehl 2012-02-27 17:26:54

+0

@nerozehl:阅读我的答案,重载决议只考虑参数而不考虑结果将如何使用。在这种情况下,因为矢量不是常量,所以它会选择'iterator begin();'作为'vec.begin()'调用的最佳候选。 – 2012-02-27 17:28:14

1

它正在选择通用版本,因为您传递的是vector<uint8_t>::iterator而不是vector<uint8_t>::const_iterator。您应该添加第三个operator(),采用非const版本并将其传递给const