将引用显式传递到不需要引用的函数模板中会导致问题吗?
Can it cause problems to explicitly pass a reference into a function template that's not expecting one?
有一个关于传递下列函数模板的问题,并且用引用字符串参数实例化它:
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的要求是透明的。)
template <typename T>
void foo(T& t) {}
(有可能他有意让这两种情况都成为可能,但出于某种原因,我觉得这似乎不太可能)
是否有任何"合理"的情况下,传递引用到
foo<T>
,其中foo
的作者有意图函数总是取其值的参数,可能会导致问题?我正在寻找的答案最有可能由
foo
的函数体组成,其中T
的引用类型的使用与T
的值类型的使用相比会导致意外/不希望的语义。
考虑这样写算法是很常见的:
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* &
或reference-to-library-iterator不是。
只要模板函数的作者清楚地记录了他们的模板实参的需求,我怀疑通常就会以与标准算法和迭代器相同的方式出现——引用类型不是有效的模板实参,因此调用者有错。在需求非常简单的情况下(具有指定行为的两个表达式),引用类型可能不被排除,但是只要函数没有说它不修改参数,也没有说如何修改参数,调用者应该考虑,因为没有记录参数如何修改,那么它是未指定的。如果他们使用引用类型调用函数,并且对参数是否被修改或如何被修改感到惊讶,那么这也是调用者的错误。
我希望文档不充分的函数在出错时可能会有争议,因为有时它依赖于相当仔细的阅读。
如果程序员决定偷懒,并使用输入参数作为临时变量来计算输出,那么您将得到有问题的结果:
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;
}
现在如果我通过引用传递第一个形参,它的值就乱了。
不是说这是好的编程,只是说它发生了。
- C++ - 对 PCM::getInstance() 的未定义引用问题
- 通过键入的引用问题传递函数
- printf(时差程序)中的引用问题
- 在一个简单的程序中奇怪的通过引用问题传递
- 在实现OpenSceneGraph时在Qt中获取引用问题
- antlr4 c++目标的未定义引用问题
- 基本指针/引用问题
- 通过引用问题传递C++
- C++ OpenMP 任务 - 通过引用问题传递
- C/C++ 双指针取消引用问题
- Q字符串传递引用问题
- Q_OBJECT导致"未定义对v_table引用"问题
- 具有最小"extern"使用测试用例的未定义引用问题
- 下标操作符重载:返回引用问题
- LuaJIT FFI中的指针和引用问题
- c++和Netbeans的未定义引用问题
- 指针和引用问题
- void*指针中的引用问题
- Crypto++ Code::blocks未定义引用问题
- 使用 FFTW 的"未定义引用"问题