Как мне требовать семантики const_iterator в сигнатуре функции шаблона? - PullRequest
7 голосов
/ 03 февраля 2010

Я создаю конструктор, который будет принимать пару входных итераторов.Я хочу, чтобы сигнатура метода имела семантику 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.

Есть ли способ указать вызывающей стороне, что я не могу изменить входные данные?

edit, 2010-02-03 16:35 UTC

В качестве примера того, как я хотел бы использовать функцию, я хотел бы иметь возможность передать пару указателей char*и знаю, основываясь на сигнатуре функции, что данные, на которые они указывают, не будут изменены.
Я надеялся, что смогу избежать создания пары const char* указателей, чтобы гарантировать семантику const_iterator.В этом случае я могу быть вынужден оплатить шаблонный налог.

Ответы [ 5 ]

9 голосов
/ 03 февраля 2010

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

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

2 голосов
/ 04 февраля 2010

Вы можете просто создать фиктивную функцию, которая вызывает ваш шаблон с char * const указателями.Если ваш шаблон пытается изменить их цели, то ваша фиктивная функция не будет компилироваться.Затем вы можете поместить указанный манекен в #ifndef NDEBUG охрану, чтобы исключить его из релизных сборок.

2 голосов
/ 03 февраля 2010

А как же

#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);
}
0 голосов
/ 03 февраля 2010

Это легко (но не красиво), если вы можете позволить себе повышение:

#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)
...
0 голосов
/ 03 февраля 2010

Этот векторный конструктор получает свои аргументы по значению, что означает, что итераторы вызывающей стороны копируются перед использованием в конструкторе, что, конечно, означает, что с итераторами вызывающей стороны ничего не происходит.

const длявходные аргументы действительно имеют значение, только когда вы передаете по ссылке.например,

void foo(int& x)

против

void foo(const int& x)

В первом примере ввод вызывающего абонента для x может быть изменен с помощью foo.Во втором примере это не может быть, так как ссылка const.

...