编译器认为我正在传递 std::ofstream*&,传递 std::ofstream*

Compiler thinks I am passing std::ofstream*&, passing std::ofstream*

本文关键字:std ofstream 传递 编译器      更新时间:2023-10-16

我最近编写了一个日志记录器类。当编译这段代码时:

std::ofstream *stream = new std::ofstream;
stream->open( log_file_name.c_str() );
assert( stream->is_open() );
logger( stream, std::string("blurp") );

我得到错误:

no match for call to '(name::space::logger)( std::ofstream*&, std::string )'

关于最后一行代码。

定义logger的头文件是:

namespace name {
    namespace space {
        class logger {
private:                
            std::ofstream *stream;
            std::string name;
public:                
            void log( std::string, std::string );
            logger( std::ofstream *, std::string );
            logger();
        };
    }
}

我已经实现了所有的函数/构造函数原型,没有错误。

是什么原因导致的?谢谢你的时间,Erkling。

编译器认为你在一个叫做logger的对象上调用operator()。似乎你想做的是创建一个logger实例:

logger log(stream, std::string("blurp") );

这里,logname::space::logger类的一个实例。

GCC有一种奇怪的方式来报告函数的参数类型。

当你这样做的时候:

logger( stream, std::string("blurp") );

编译器看到对记录器构造函数(name::space::logger)的调用,其中第一个参数是类型为std::ostream*的左值(在本例中是一个普通变量),第二个参数是类型为std::string的右值(就地临时构造)。它将此报告为呼叫签名(name::space::logger)(std::ostream*&, std::string) - &(左值引用)在这里仅表示参数是左值。这并不影响将其与参数类型std::ostream*匹配的能力。

首先,ostream不需要使用指针。因为这不是Java,所以您可以在堆栈上创建对象,而不需要new

那么看起来好像编译器没有看到logger的构造函数接受一个流指针和一个字符串。从调用开始,它假设签名必须是,例如 std::ofstream*&, std::string,但是您提供的构造函数完全符合该假设(详细信息请参阅Sebastian Redl的回答)。

那么,这里有什么问题呢?

  1. 编译器根本看不到头文件。那是因为你没有把它包括进去。我不认为这是可能的,因为错误信息应该是不同的,然后(说一些关于类logger尚未定义)
  2. 编译器看到另一个版本的头文件,其中不包含你在这里要调用的构造函数。这可能是因为您在构造函数中编辑后没有保存头文件,或者可能您将其复制到另一个位置,#include指令找到一个旧版本,而不是您放入构造函数的版本。最好的方法是在头文件中引入一些明显的错误,然后重新编译。如果编译器没有报错,说明它显然不包括你正在编辑的头文件。