How do I require const_iterator semantics in a template function signature?

旧城冷巷雨未停 提交于 2019-12-12 09:38:40

问题


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.


回答1:


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:


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.




回答3:


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



回答4:


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.




回答5:


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)
...


来源:https://stackoverflow.com/questions/2193399/how-do-i-require-const-iterator-semantics-in-a-template-function-signature

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!