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

时间:2011-07-23 16:46:59

标签: c++ templates reference

关于传递采用以下函数模板有a question使用按引用字符串参数实例化它:

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(),并且OP的要求是透明度。)

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

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

(他有可能故意让两者成为可能,但出于某种原因这似乎不太可能。)

  • 是否有任何“合理”的情况,其中将引用传递到foo<T>,其中foo的作者意图该函数始终通过价值,可能会引起问题吗?

  • 我正在寻找的答案很可能包含foo的函数体,其中使用T的引用类型会导致意外/不合需要的语义使用T的值类型。

2 个答案:

答案 0 :(得分: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;
}

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

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

答案 1 :(得分:7)

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

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

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

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

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

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

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

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