将引用明确地传递给不期望的函数模板会导致问题吗?

Lig*_*ica 3 c++ templates reference

一个关于传递以下函数模板的问题,并使用by-reference字符串参数对其进行实例化:

template <typename T>
void foo(T t) {}
Run Code Online (Sandbox Code Playgroud)

答案当然是明确地给出论点:

int main() {
   std::string str("some huge text");
   foo<std::string&>(str);
}
Run Code Online (Sandbox Code Playgroud)

(顺便说一下,有一个关于使用演绎和传递C++ 0x的建议std::ref(str),但这需要.get()在函数内部使用,而OP的要求是透明的.)

但是,IMO毫无疑问,函数模板的作者打算通过值传递参数,或者他会写:

template <typename T>
void foo(T& t) {}
Run Code Online (Sandbox Code Playgroud)

(他有可能故意为这两种方式做出准备,但出于某种原因,这似乎不太可能.)

  • 是否有任何"合理"的场景中传递引用到foo<T>,这里笔者foo预期的功能始终采取按值它的参数,可能会导致问题?

  • 我正在寻找的答案最有可能包括一个函数体foo,与使用T值类型相比,使用引用类型会导致意外/不良语义T.

Yoc*_*mer 7

如果程序员决定是懒惰的,并使用输入参数作为临时变量来计算输出,那么你会得到有问题的结果:

template <class T>
T power2n(T a, int n) {
    if (n == 0) return 1;
    for (int i = 0 ; i < n; i++) 
    {
       a *= a; 
    }
    return a;
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我通过引用传递第一个参数,它的值就会搞砸了.

不是说这是好的编程,只是说它发生了.


Ste*_*sop 7

考虑一下编写这样的算法很常见:

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

这也是GCC和旧SGI STL中标准算法的实现方式.

如果first通过引用获取它然后它将被修改,所以当然有很多模板函数会出现参考模板参数"出错".在此示例中,first将更改为等于的值last.在另一个实现中,或者在下一个版本中,它可能被复制而根本不被修改.这是"意外/不受欢迎的语义".

不管你是否称之为"问题",我都不确定.这不是函数作者所期望的行为,并且可能没有记录first如果它通过引用传递会发生什么(它不是标准算法).

对于标准算法,我认为它是UB,因此调用者有错.标准说模板参数应该是一个迭代器,而T*某些库迭代器是迭代器类型,T* &或者引用到库的迭代器不是.

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

我希望记录不足的函数存在争议的风险,但是当它出错时,它会出现错误,因为有时它会依赖于非常接近的读数.