Я пишу вспомогательную функцию для ведения журналов: она собирает информацию о месте вызова и одновременно создает Error
-типированный объект.
template<typename ErrorTy, typename... ArgTys>
std::unique_ptr<Error> makeError(const char* fileName = __builtin_FILE(),
int lineNum = __builtin_LINE(),
const char* funcName = __builtin_FUNCTION(), ArgTys &&... args) {
return std::make_unique<ContextualError<ErrorTy>>(fileName, lineNum, funcName,
std::forward<ArgTys>(args)...);
}
// ...
template<typename ErrorTy>
struct ContextualError : ErrorTy {
template<typename... ArgTys>
ContextualError(std::string_view fileName, int lineNum,
std::string_view funcName, ArgTys &&... args) :
fileName_(fileName), lineNum_(lineNum), funcName_(funcName),
ErrorTy(std::forward<ArgTys>(args)...) {}
// ...
};
Поскольку фактические классы Error
могут иметь произвольные конструкторы, я надеялся получить makeError
и конструктор ContextualError
, чтобы все отлично пересылать. К сожалению, вызов makeError
подобным образом попытается заполнить первые три необязательных аргумента, а не пропускать их и заполнять пакет параметров:
auto err = makeError<FileError>("foo.exe", "Invalid header");
// error: no matching function for call to 'makeError'
// note: candidate function template not viable: no known conversion
// from 'const char [15]' to 'int' for 2nd argument
// It's trying to replace the default values:
auto err = makeError<FileError>(fileName: "foo.exe", lineNum: "Invalid header", funcName: __builtin_FUNCTION(), args...: );
// But I only want to supply the parameter pack args:
auto err = makeError<FileError>(fileName: __builtin_FILE(), lineNum: __builtin_LINE(), funcName: __builtin_FUNCTION(), args...: "foo.exe", "Invalid header");
Перемещение пакета параметров в начало списка аргументов не ' Кажется, это тоже можно исправить. Есть ли способ достичь этой идеальной пересылки, сохраняя необязательные аргументы?
Минимальный воспроизводимый пример на Godbolt