7

I am creating a constructor that will take a pair of input iterators. I want the method signature to have compile-time const semantics similar to:

DataObject::DataObject(const char *begin, const char *end)

However, I can't find any examples of this. For example, my STL implementation's range constructor for vector is defined as:

template<class InputIterator>
vector::vector(InputIterator first, InputIterator last)
{
    construct(first, last, iterator_category(first));
}

which has no compile-time const guarantees. iterator_category / iterator_traits<> contain nothing relating to const, either.

Is there any way to indicate to guarantee the caller that I can't modify the input data?

edit, 2010-02-03 16:35 UTC

As an example of how I would like to use the function, I would like to be able to pass a pair of char* pointers and know, based on the function signature, that the data they point at will not be modified.
I was hoping I could avoid creating a pair of const char* pointers to guarantee const_iterator semantics. I may be forced to pay the template tax in this case.

2
  • Is this the kind of thing that compiler-enforced concepts would be good for? I don't remember if the proposal said anything about const requirements. Commented Feb 3, 2010 at 18:04
  • I think the best possible option at this point is to explicitly instantiate the function using a const char * and rely on that as my compile-time check for all other types. Commented Feb 3, 2010 at 20:46

5 Answers 5

10

The caller can simply use the template with const iterators. If he does, and the compiler doesn't complain, it is guaranteed that the function doesn't modify the data. If it would modify the data, instantiating the template with a const iterator would lead to errors.

You don't really have to force the caller to use const iterators just because you don't modify anything.

Sign up to request clarification or add additional context in comments.

10 Comments

+1... and to say I got to all the trouble of indicating how to do it!
The semantics of the DataObject example mean that I can pass in non-const pointers and have them treated as const pointers. I don't want to force the caller to use const iterators - I just want to guarantee that they will only be used as const iterators.
Either you make defensive copies of the data so it doesn't change (internal const char*), or you document your requirements and move on with life.
That's the thing. I'm trying to get the function signature to both document and defend, just like I can do with const char * parameters.
@mskfisher: There is no point to go out of your way over this. For documentation simply call the template parameter ConstIterator if you must, test that the function compiles if given const iterators, and move on.
|
2

You could simply create a dummy function which calls your template with char * const pointers. If your template attempts to modify their targets, then your dummy function will not compile. You can then put said dummy inside #ifndef NDEBUG guards to exclude it from release builds.

2 Comments

This is more like it. This gives me the compile-time assurance I was looking for.
... although for my purposes, I think you mean const char * pointers.
2

What about

#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);
}

2 Comments

You prevent template parameter deduction by using inner types.
Good idea, but I don't have a const_iterator here because I'm passing in two char * as iterators.
0

That vector constructor is receiving its arguments by value, which means that the caller's iterators are copied before being used in the constructor, which of course means that nothing happens to the caller's iterators.

const for input arguments only really matter when you are passing by reference. e.g.

void foo(int& x)

vs

void foo(const int& x)

In the first example, the caller's input for x may be modified by foo. In the second example, it may not, as the reference is const.

2 Comments

Sorry, I wasn't completely clear in my question. I want to ensure that the data that the iterators are pointing at is guaranteed to be treated as const, not that the iterators themselves should be const.
A const_iterator cannot be used to modify the element of the container it's iterating. An ordinary iterator can be used that way, even if it's passed by const reference. (Simply make a non-const copy of it.) The types const iterator and const_iterator aren't the same things.
0

This is easy (but not pretty) if you can afford boost:

#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
}

EDIT: if you want to have and indication about this in your signature then it's common to exploit the name of the template parameter:

template<class ConstIt>
void f(ConstIt b, ConstIt e)
...

2 Comments

As I understand the point of the question is only to make sure that the function itself cannot modify the sequence. The point is not to force the user to manually cast things to const iterators.
Like I said in my comment to @sth, I want to require that the iterator can be used as a const_iterator, just like a random-access iterator can be used as a forward iterator.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.