首页 > 解决方案 > 混合使用可变参数的默认值 arg

问题描述

问题代码:

#include <filesystem>
#include <iosfwd>
#include <string>
#include <format>
#include <source_location>
#include <iostream>
#include <array>
#include <wchar.h>
#include <fstream>
#include <memory>
#include <exception>

using std::filesystem::path;
using std::array;
using std::source_location;
using std::format;
using std::vformat;
using std::wstring;

class CStreamToTextFileU {
    std::unique_ptr<std::wofstream>  m_pFileStr;
              CStreamToTextFileU() = delete;
public:
    explicit  CStreamToTextFileU(const std::filesystem::path& Filepath, std::ios::openmode nMode) :
                  m_pFileStr(std::make_unique<std::wofstream>(Filepath, nMode | std::ios::out)) {
                  if((m_pFileStr.get() == nullptr) || (! m_pFileStr->is_open()))
                      throw std::ios::failure("Unable to open file for writing");
              }
              CStreamToTextFileU(CStreamToTextFileU&& Other) noexcept : m_pFileStr(std::move(Other.m_pFileStr)) {}
              CStreamToTextFileU &operator=(CStreamToTextFileU&& Other) & noexcept {
                  if(this != &Other)
                      m_pFileStr = std::move(Other.m_pFileStr);
                  return(*this);
              }
             ~CStreamToTextFileU() noexcept {
                  if(m_pFileStr != nullptr)
                      m_pFileStr->close();
              }
    std::wofstream& operator()() const { return(*(m_pFileStr.get())); }
};

class RLog {
                CStreamToTextFileU    LogStream;
public:
                RLog() = delete;
    explicit    RLog(const path Filepath);
                template<auto Separator = L' ', typename... Args>
    void        LogMsg(Args&&... args, const std::source_location Cur = std::source_location::current());
};  // class RLog()
//                template<typename... Args> LogMsg(Args&&...) -> LogMsg<Args...>;

RLog::RLog(const path Filepath) : LogStream(CStreamToTextFileU(Filepath, std::ios::trunc)) {
    LogStream() << L"Log file: " << Filepath << L"\n\n";
}   // RLog::RLog()

template<auto Separator, typename... Args>
void RLog::LogMsg(Args&&... args, const std::source_location Cur) {
    static int n{};
    RLog::LogStream() << format(L"{:04} File: {}({}:{}) `{}`:",
                          n++, Cur.file_name(), Cur.line(),
                          Cur.column(), Cur.function_name());
    (... , [] (const auto&& arg) -> const auto { RLog::LogStream() << Separator
                                                                   << std::forward<Args>(arg); } (args));
    RLog::LogStream() << L'\n';
}   // RLog::LogMsg()

int main() {
    path LogPath {L"RLogFile.txt"};
    RLog Lg {LogPath};
    Lg.LogMsg(L"This is an", L"error", L'\n');
}   // main()

我正在用最新的 VS 编译。引用的代码将使用最新的 x86 VS 编译器和标志 /std:c++latest 在编译器资源管理器中运行。我得到的错误是:

example.cpp
<source>(70): error C2672: 'RLog::LogMsg': no matching overloaded function found
<source>(70): error C2780: 'void RLog::LogMsg(Args &&...,const std::source_location)': expects 2 arguments - 3 provided
<source>(48): note: see declaration of 'RLog::LogMsg'
Compiler returned: 2

我尝试了多种方法来解决这个问题,包括不同的参数顺序、将 LogMsg() 嵌入嵌套结构中、使 source_location 参数成为模板参数(不能从默认值推断)等等。注释掉的推导指南可以修复它,但它不起作用,因为问题函数是成员,而不是构造函数,所以编译器只是将其视为损坏的函数声明。

代码的想法应该很明显:在包含您要记录的所有位置的范围内调用类构造函数,然后调用 LogMsg() 函数来创建日志消息。我宁愿不离开这个计划。我知道我可以通过打开和关闭每条消息的文件流来解决问题,因为那样整个事情都可能在类构造函数中,但这似乎不优雅,我宁愿让它工作。

标签: c++c++20

解决方案


推荐阅读