1

只是一个我在使用 stl 时发现有趣的问题。在下面的代码中,主函数中的最后两行将导致错误(在注释中指出)。但是, 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

}

更新:我在使用 bind1st 和 bind2nd 函数时遇到了这个问题;它们的定义就像教科书中的 test_func 一样(第 18 章关于活页夹的部分中的 stroustrup),所以它不会出错。

4

2 回答 2

2

注释的第一行是合法的,您的编译器可能不符合 C++11。由于 C++11 的引用折叠规则,实际上它应该声明一个对Filenamed的左值引用fRef1并将其绑定到左值f

注释的第二行是非法的:您不能将右值引用绑定到左值。但是,您收到的错误似乎表明编译器不理解&&令牌。

如果您使用 Clang 或 GCC,请确保使用-std=c++11or-std=c++0x选项进行编译。

更新:

在 C++03 中,这两行都是非法的,甚至这个函数调用也应该被编译器拒绝:

test_func<File&>(f); // SHOULD BE AN ERROR! (substitution failure)

根据 C++03 标准的第 14.8.2/2 段:

[...]类型扣除可能会因以下原因而失败:

— [...]

试图创建对引用类型的引用或对 void 的引用。

— [...]

这可能意味着两件事:您的编译器有错误,或者它故意决定忽略在模板参数推导的上下文中(并且仅在该上下文中)创建对引用的引用的尝试 - 这意味着您正在处理一个编译器扩展。

无论如何,该函数调用格式不正确,因此不可移植。

于 2013-06-12T17:34:09.130 回答
0

我认为该函数有效,因为编译器足够聪明,不会引用引用。他得到一个参考并想要一个参考,所以它保持不变。我认为他只是忽略了第二个 & 当你有 T& 而 T 已经是一个参考。我无法详细解释它,但在 C++ 中,您可以像使用非引用一样使用引用。

FileRef&不能忽视这一点。在这里你明确地说:做一个引用的引用,什么都行不通。&& 是一个逻辑与。

ps:替换失败不是错误(SFINAE)

于 2013-06-12T18:28:15.783 回答