Заполнение пакета параметров путем пропуска необязательных аргументов - PullRequest
1 голос
/ 14 января 2020

Я пишу вспомогательную функцию для ведения журналов: она собирает информацию о месте вызова и одновременно создает 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

1 Ответ

5 голосов
/ 14 января 2020
template<class ErrorTy>
auto makeError(
    const char* fileName = __builtin_FILE(),
    int lineNum = __builtin_LINE(),
    const char* funcName = __builtin_FUNCTION()
) {
  return [=](auto&&... args) {
    return std::make_unique<ContextualError<ErrorTy>>(
      fileName, lineNum, funcName,
      decltype(args)(args)... // yes, this perfect fowards
    );
  };
}

использование:

auto err = makeError<FileError>()("foo.exe", "Invalid header");

см. Дополнительные (). Необязательные аргументы go в () и переадресованные аргументы go во второй набор ().

Живой пример, основанный на вашем .

Вы также можете сделать makeError a class и дать ему operator(), который делает фактическую ошибку, и дать ему аргументы по умолчанию для его ctor. Тогда вы получите:

auto err = makeError<FileError>{}("foo.exe", "Invalid header");

, который может быть менее запутанным или более запутанным. Один из них.

...