它可以引起问题明确传递一个引用到一个不期望的函数模板? [英] Can it cause problems to explicitly pass a reference into a function template that's not expecting one?

查看:137
本文介绍了它可以引起问题明确传递一个引用到一个不期望的函数模板?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

a问题,并且使用按引用字符串参数来实例化:



  template< typename T> 
void foo(T t){}

答案当然是参数显式:

  int main(){
std :: string str(some huge text);
foo< std :: string&>(str);
}

(另外,有人建议使用扣除和传递C ++ 0x的 std :: ref(str),但这需要使用 .get() inside函数和OP的要求是透明的。)



但是,IMO毫不怀疑函数模板的作者要通过值传递的参数,否则他会写成:

  template< typename T& 
void foo(T& t){}




  • 是否有可能在 foo 中传递引用的任何合理场景,其中 foo

    我想找的答案最有可能包含一个函数body的 foo ,其中使用 T 的引用类型会导致意外/ T 的值类型。



解决方案

考虑这样写算法很常见:

  template< typename InputIterator> 
void dosomething(InputIterator first,InputIterator last,otherparams){
while(first!= last){
do the work;
++ first;
}
}

这也是标准算法如何在GCC并在旧的SGI STL中。



如果第一个是通过引用,那么它将被修改,所以肯定有很多模板函数将使用引用模板参数出错。在此示例中,第一更改为等于 last 的值。在另一个实现中,或者在下一个版本中,它可能被复制并且根本不被修改。这是意外/不受欢迎的语义。



无论你是不是称之为问题,我不确定。这不是该函数的作者想要的行为,并且可能没有记录如果通过引用传递(不是标准算法),第一会发生什么。



对于标准算法,我认为它是UB,所以调用者是错误的。标准说模板参数应该是一个迭代器,而 T * 或者一些库迭代器是一个迭代器类型, T *& code>或引用到库迭代器不是。



只要模板函数的作者清楚地记录了其模板参数的要求,怀疑通常它将以与标准算法和迭代器相同的方式出现 - 引用类型不是有效的模板参数,因此调用者是错误的。在需求非常简单(具有指定行为的几个表达式)的情况下,引用类型可能不排除,但是只要函数不表示 >修改参数,并且不说如何修改参数,调用者应该考虑,因为它没有记录如何修改参数,那么它是未指定的。如果他们调用一个引用类型的函数,并惊讶是否或如何修改参数,这也是调用者的错误。



我期望,有争议的风险,它的错误是错误的,虽然,因为有时它会依靠相当仔细的阅读。


There was a question regarding passing taking the following function template, and instantiating it with a by-reference string parameter:

template <typename T>
void foo(T t) {}

The answer was, of course, to give the argument explicitly:

int main() {
   std::string str("some huge text");
   foo<std::string&>(str);
}

(As an aside, there was a suggestion about using deduction and passing C++0x's std::ref(str), but this requires the use of .get() inside the function, and the OP's requirement was transparency.)

However, IMO there can be little doubt that the author of the function template intended for the argument to be passed by value, or he would have written:

template <typename T>
void foo(T& t) {}

(It's possible that he deliberately intended for either to be possible, but this seems unlikely to me for some reason.)

  • Are there any "reasonable" scenarios where passing a reference into foo<T>, where the author of foo had intended the function always to take its argument by value, may cause problems?

  • The answer I'm looking for most likely consists of a function body for foo, where the use of a reference type for T leads to unexpected/undesirable semantics when compared to the use of a value type for T.

解决方案

Consider that it's common to write algorithms like this:

template <typename InputIterator>
void dosomething(InputIterator first, InputIterator last, otherparams) {
    while (first != last) {
        do the work;
        ++first;
    }
}

It's also how the standard algorithms are implemented both in GCC and in the old SGI STL.

If first is taken by reference then it will be modified, so certainly there are plenty of template functions out there that will "go wrong" with reference template arguments. In this example, first is changed to a value equal to last. In another implementation, or in the next release, it might be copied and not modified at all. That's "unexpected/undesirable semantics".

Whether you call this a "problem" or not, I'm not sure. It's not the behavior that the author of the function intended, and it's probably not documented what happens to first if it's passed by reference (it isn't for the standard algorithms).

For the standard algorithms I think it's UB, so the caller is at fault. The standard says that the template argument should be an iterator, and while T* or some library iterator is an iterator type, T* & or reference-to-library-iterator isn't.

As long as authors of template functions have documented the requirements of their template arguments clearly, I suspect that typically it will just fall out in the same way as for standard algorithms and iterators -- reference types are not valid template arguments, and hence the caller is at fault. In cases where the requirements are very simple (a couple of expressions with specified behavior), a reference type probably isn't ruled out, but again as long as the function doesn't say that it doesn't modify the argument, and doesn't say how it modifies the argument, callers should consider that since it's not documented how the argument is modified, then it's unspecified. If they call the function with a reference type, and get surprised whether or how the argument is modified, again it's the caller's fault.

I expect that under-documented functions are at risk of a dispute whose fault it is when it goes wrong, though, since sometimes it'll rely on quite a close reading.

这篇关于它可以引起问题明确传递一个引用到一个不期望的函数模板?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆