C++ C++;嵌套引用直接vs通过模板参数
我在使用stl时发现了一个有趣的问题。在下面的代码中,main函数的最后两行将导致错误(在注释中指出)。但是,test_func编译得很好。既然传递给模板函数的类型是引用类型,并且函数本身应用了&运算符,那么这两种类型本质上不一样吗?显然不是因为其中一个编译,另一个不编译。有人知道为什么吗C++ C++;嵌套引用直接vs通过模板参数,c++,templates,reference,nested,C++,Templates,Reference,Nested,我在使用stl时发现了一个有趣的问题。在下面的代码中,main函数的最后两行将导致错误(在注释中指出)。但是,test_func编译得很好。既然传递给模板函数的类型是引用类型,并且函数本身应用了&运算符,那么这两种类型本质上不一样吗?显然不是因为其中一个编译,另一个不编译。有人知道为什么吗 class File { private: std::string name_; public: File(std::string n)
class File {
private:
std::string name_;
public:
File(std::string n) : name_(n) {}
std::string name() const { return name_; }
};
std::ostream& operator<<(std::ostream& os, const File& f)
{
os << f.name();
return os;
}
template <class T> void test_func(const T& v)
{
T& v1(v);
std::cout << "File:" << v1 << std::endl;
}
typedef File& FileRef;
int main(int argc, char* argv[])
{
File f("test_file");
test_func<File&>(f);
// FileRef& fRef1(f); ==> error; cannot declare reference to 'class File&'
// File&& fRef2(f); ==> error; expected unqualified-id before '&&' token
}
类文件{
私人:
std::字符串名称;
公众:
文件(std::string n):名称{(n){}
std::string name()常量{返回名称}
};
std::ostream&operator第一行注释是合法的,并且您的编译器可能不符合C++11。由于C++11的引用折叠规则,实际上,它应该声明一个名为fRef1
的File
的左值引用,并将其绑定到左值f
第二条注释行是非法的:不能将右值引用绑定到左值。但是,您得到的错误似乎表明编译器不理解&&
标记
如果您使用的是Clang或GCC,请确保使用-std=c++11
或-std=c++0x
选项进行编译
更新:
在C++03中,这两行都是非法的,即使是此函数调用也应被编译器拒绝:
test_func<File&>(f); // SHOULD BE AN ERROR! (substitution failure)
test_func(f);//应该是个错误!(替换失败)
根据C++03标准第14.8.2/2段:
[…]类型扣减可能会失败
原因如下:
-[……]
-试图创建对引用类型的引用或对void的引用
-[……]
这可能意味着两件事:要么您的编译器有一个bug,要么它故意决定忽略在模板参数推断上下文中(并且仅在该上下文中)创建引用的尝试,这意味着您正在处理编译器扩展
在任何情况下,该函数调用的格式都不正确,因此不可移植。我认为该函数可以工作,因为编译器足够聪明,不会引用引用。他得到了一份推荐信,并且想要一份推荐信,所以它一直是一份。我认为他只是忽略了第二个&当你有T时,T已经是一个参考。
我不能详细解释,但是在C++中,你可以使用与非引用完全一样的引用。
在FileRef&
中,他不能忽视这一点。这里你明确地说:引用一个引用,什么不能工作。
And&&是逻辑And
ps:替换失败不是一个错误(SFINAE)即使我使用FileRef&fRef1=f,它也是相同的错误;文件&&fREf2=f;我使用的是gcc版本4.4.6。所以如果我没有使用C++11,那么第一行是非法的,对吗?如果是这样,那么为什么test_func会成功?这和第一行有什么不同。@PurushothamNayak:对不起,我之前的评论不正确。这个函数调用应该是非法的,但如果替换失败后没有可行的重载,那就是一个错误。