Я создаю конструктора, который возьмет пару входных итераторов. Я хочу, чтобы сигнатура метода имела время компиляции const
семантика, подобная:
DataObject::DataObject(const char *begin, const char *end)
Однако я не могу найти примеры этого. Например, мой конструктор диапазона реализации STL для vector
определяется как:
template<class InputIterator>
vector::vector(InputIterator first, InputIterator last)
{
construct(first, last, iterator_category(first));
}
который не имеет никакого времени компиляции const
гарантии. iterator_category
/ iterator_traits<>
не содержите ничего касающегося const
, также.
Там какой-либо путь состоит в том, чтобы указать, чтобы гарантировать вызывающей стороне, что я не могу изменить входные данные?
редактирование, 03.02.2010 16:35 UTC
Как пример того, как я хотел бы использовать функцию, я хотел бы смочь передать пару char*
указатели и знают, на основе функциональной подписи, что данные указывают по желанию не быть измененными.
Я надеялся, что мог постараться не создавать пару const char*
указатели для гарантии const_iterator семантики. Я могу быть вынужден заплатить шаблонный налог в этом случае.
Вы можете просто создать фиктивную функцию, которая вызывает ваш шаблон с указателями char * const
. Если ваш шаблон пытается изменить свои цели, ваша фиктивная функция не будет компилироваться. Затем вы можете поместить указанный манекен внутрь #ifndef NDEBUG
охранников, чтобы исключить его из сборок выпуска.
Вызывающий может просто использовать шаблон с константными итераторами. Если он это делает, а компилятор не жалуется, гарантируется, что функция не изменяет данные. Если он изменит данные, создание экземпляра шаблона с помощью константного итератора приведет к ошибкам.
На самом деле вам не нужно заставлять вызывающую программу использовать константные итераторы только потому, что вы ничего не изменяете.
А как насчет
#include <vector>
template <class T>
class MyClass{
public:
MyClass(typename T::const_iterator t1,typename T::const_iterator t2){
}
// *EDITED*: overload for pointers (see comments)
MyClass(const T* t1,const T* t2){
}
};
void main(){
std::vector<int> v;
std::vector<int>::const_iterator it1 = v.begin();
std::vector<int>::const_iterator it2 = v.end();
MyClass<std::vector<int> > mv(it1,it2);
// with pointers:
char* c1;
char* c2;
MyClass mc(c1,c2);
}
Этот конструктор вектора получает свои аргументы по значению, что означает, что итераторы вызывающего объекта копируются перед использованием в конструкторе, что, конечно же, означает, что ничего не происходит итераторам вызывающего.
const
для входных аргументов имеет значение только при передаче по ссылке. например
void foo (int & x)
vs
void foo (const int & x)
В первом примере ввод вызывающей стороны для x
может быть изменен с помощью foo
. Во втором примере это может быть не так, поскольку ссылка const
.
Это легко (но не красиво), если вы можете позволить себе повышение:
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
template<class It>
void f(It b, It e)
{
using namespace boost;
typedef typename std::iterator_traits<It>::reference reference;
BOOST_STATIC_ASSERT(is_const<typename remove_reference<reference>::type>::value);
}
void test()
{
f((char const*)0, (char const*)0); // Compiles
f((char*)0, (char*)0); // Does not compile
}
РЕДАКТИРОВАТЬ : если вы хотите, и указание об этом в ваша подпись, то обычно используется имя параметра шаблона:
template<class ConstIt>
void f(ConstIt b, ConstIt e)
...