C++ C++;嵌套引用直接vs通过模板参数

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)

我在使用stl时发现了一个有趣的问题。在下面的代码中,main函数的最后两行将导致错误(在注释中指出)。但是,test_func编译得很好。既然传递给模板函数的类型是引用类型,并且函数本身应用了&运算符,那么这两种类型本质上不一样吗?显然不是因为其中一个编译,另一个不编译。有人知道为什么吗

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:对不起,我之前的评论不正确。这个函数调用应该是非法的,但如果替换失败后没有可行的重载,那就是一个错误。