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

发布于 2024-08-20 00:01:03 字数 778 浏览 10 评论 0原文

我正在创建一个构造函数,它将采用一对输入迭代器。我希望方法签名具有类似于以下内容的编译时 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 语义。在这种情况下,我可能会被迫缴纳模板税。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甜`诱少女 2024-08-27 00:01:03

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

您实际上不必仅仅因为没有修改任何内容就强制调用者使用 const 迭代器。

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.

橘亓 2024-08-27 00:01:03

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

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.

π浅易 2024-08-27 00:01:03

怎么样

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

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);
}
灼疼热情 2024-08-27 00:01:03

该向量构造函数按值接收其参数,这意味着调用者的迭代器在构造函数中使用之前会被复制,这当然意味着调用者的迭代器不会发生任何事情。

仅当您通过引用传递时,输入参数的 const 才真正重要。例如

void foo(int& x)

void foo(const int& x)

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

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.

零崎曲识 2024-08-27 00:01:03

如果您能负担得起提升,这很容易(但并不漂亮):

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

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)
...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文