我必须实现一个带迭代器的函数。迭代器必须取消引用某种类型,比如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());
他会看到错误指向我的代码中的某个位置,而不是他的代码(这会让他感到困惑)。我希望错误出现在用户代码中,以便于调试。
答案 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。