如何在模板函数签名中要求const_iterator语义?

时间:2010-02-03 16:13:43

标签: c++ templates const iterator const-correctness

我正在创建一个构造函数,它将接受一对输入迭代器。我希望方法签名具有类似于:

的编译时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相关的内容。

有没有办法指示保证调用者不能修改输入数据?

编辑,2010-02-03 16:35 UTC

作为我想如何使用该函数的一个例子,我希望能够传递一对char*指针并根据函数签名知道它们指向的数据不会被修改 我希望我能避免创建一对const char*指针来保证const_iterator语义。在这种情况下,我可能会被迫支付模板税。

5 个答案:

答案 0 :(得分:9)

调用者可以简单地将模板与const迭代器一起使用。如果他这样做,并且编译器没有抱怨,则保证该函数不会修改数据。如果它会修改数据,用const迭代器实例化模板会导致错误。

您不必仅仅因为不修改任何内容而强制调用者使用const迭代器。

答案 1 :(得分:2)

怎么样?
#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 :(得分:2)

您可以简单地创建一个虚拟函数,使用char * const指针调用模板。如果您的模板试图修改其目标,那么您的虚拟函数将无法编译。然后,您可以将所述虚拟内部放在#ifndef NDEBUG防护中,以将其从发布版本中排除。

答案 3 :(得分:0)

该向量构造函数通过值接收其参数,这意味着调用者的迭代器在构造函数中使用之前被复制,这当然意味着调用者的迭代器没有任何反应。

输入参数的

const仅在您通过引用传递时才真正重要。 e.g。

void foo(int& x)

VS

void foo(const int& x)

在第一个示例中,x的来电者输入可能会被foo修改。在第二个示例中,它可能不是,因为引用是const

答案 4 :(得分:0)

如果你能负担得起,这很容易(但不是很漂亮):

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