确保迭代器取消引用某种类型

时间:2010-07-14 21:50:43

标签: c++

我必须实现一个带迭代器的函数。迭代器必须取消引用某种类型,比如int:

template<typename iter>
  void f(iter i) {
  // do something here ...
  int t = *i;
  // do something here ...
}

此代码的问题在于,如果用户调用此函数

vector<string> v;
v.push_back("aaa");
f(v.begin());

他会看到错误指向我的代码中的某个位置,而不是他的代码(这会让他感到困惑)。我希望错误出现在用户代码中,以便于调试。

4 个答案:

答案 0 :(得分:6)

GMan已经指出了一种通过编译时断言来解决这个问题的方法。还有另一种方法可以做到这一点,我更喜欢(这是我最喜欢的C ++技术)。如果约束不适合,您可以以函数忽略的方式对函数参数设置约束以进行重载解析。这非常棒,因为您可以将函数重载微调到任意条件。方法如下:

#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <vector>


template<typename Iter> typename
boost::enable_if<
    boost::is_same<typename Iter::value_type,int>,
void>::type
foo(Iter it) { }

int main() {    
    std::vector<int> v; // this is OK
    foo(v.begin());
    std::vector<double> v2; // this is an error
    foo(v2.begin()); }

如果你编译它,你会得到

b.cc: In function 'int main()':
b.cc:19:16: error: no matching function for call to 'foo(std::vector<double>::iterator)'

这是因为编译器只考虑foo(),如果它的参数内部有一个value_type类型,那就是'int'(这就是enable_if部分的含义)。 foo()的第二次调用不能满足这个约束。

在SO中提及了几次

enable_if,只需搜索它:https://stackoverflow.com/search?q=enable_if

答案 1 :(得分:4)

你可以这样做:

#include <boost/type_traits/is_convertible.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/mpl/assert.hpp>

template <typename Iter>
void foo(Iter pIter)
{
    BOOST_MPL_ASSERT_MSG(
        (boost::is_convertible<BOOST_TYPEOF(*pIter), int>::value),
        DEREFERENCED_ITERATOR_MUST_BE_CONVERTIBLE_TO_INT,
        (int));

    // ...
}

#include <vector>
#include <string>

int main(void)
{
    std::vector<std::string> v(5);

    foo(v.begin());
}

这使得消息非常明显:

  

错误C2664:'boost :: mpl :: assertion_failed':无法从'boost :: mpl :: fail ************转换参数1(__ thiscall foo :: DEREFERENCED_ITERATOR_MUST_BE_CONVERTIBLE_TO_INT :: * ***********)(int)'到'boost :: mpl :: assert :: type'

但正如詹姆斯所说,大多数编制者都会提供大量信息来了解发生了什么。

答案 2 :(得分:1)

鉴于有问题的代码,大多数编译器将引用诊断消息中的实例化点。对于以下内容,第16行是f(v.begin());行。

Microsoft Visual C ++报告:

> c:\example\main.cpp(16) : see reference to function template instantiation 'void f<std::_Vector_iterator<_Myvec>>(iter)' being compiled
1>          with
1>          [
1>              _Myvec=std::_Vector_val<std::string,std::allocator<std::string>>,
1>              iter=std::_Vector_iterator<std::_Vector_val<std::string,std::allocator<std::string>>>
1>          ]

g ++报告:

main.cpp:16:   instantiated from here

英特尔C ++编译器和Comeau都报告:

detected during instantiation of
                "void f(iter) [with iter=std::string *]" at line 16

答案 3 :(得分:0)

您需要在通用类型上设置constraint