2010-07-14 2 views
2

Мне нужно реализовать функцию, которая принимает итератор. Итератор должен разыменование к определенному типу, скажем, 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

Мне нравится решение Лютера Блиссетт в своей естественной продукции (когда пользователь видит «не соответствие функции ...«он начинает проверять тип аргументов и не предполагает, что в моей функции есть ошибка). Кроме того, решение GMan очень хорошо, потому что оно явно сообщает, в чем проблема. –

ответ

6

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

#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 внутри, который является «ИНТ '(Это то, что означает часть enable_if). Второй вызов foo() не может удовлетворить этому ограничению.

enable_if упоминается несколько раз в SO, просто искать его: https://stackoverflow.com/search?q=enable_if

1

Учитывая данный код, большинство компиляторов будут ссылаться на точку инстанцирования в диагностическом сообщении. Для строки 16 приведена строка f(v.begin());.

++ отчеты Visual C Microsoft:

> 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>   ] 

г ++ отчеты:

main.cpp:16: instantiated from here 

Intel C++ Compiler и Комео как отчет:

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

Вы должны установить constraint на родовое тип.

+2

Это не C++, а вариант (Microsoft не сообщит вам об этом, прочитав эту страницу.) – GManNickG

+0

@GMan: На самом деле это похоже на то, что эта страница находится в разделе «Особенности языка для таргетинга на CLR» –

+0

@James: Хорошо , так что, может быть, я просто тупой, но все же ...: P – GManNickG

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: 'повышение :: MPL :: assertion_failed': не удается преобразовать параметр 1 из ' boost :: mpl :: failed ************ (__ thiscall foo :: DEREFERENCED_ITERATOR_MUST_BE_CONVERTIBLE_TO_INT :: * ***********) (int) 'to' boost :: mpl :: assert: type '

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

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