mardi 14 janvier 2020

Filling a parameter pack by skipping optional arguments

I'm writing a helper function for logging purposes: it collects call-site information while also creating a Error-typed object.

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)...) {}

    // ...
};

As the actual Error classes can have arbitrary constructors, I was hoping to get makeError and the ContextualError constructor to perfectly forward everything. Unfortunately, calling makeError like this will try to fill the first three optional arguments, rather than skipping them and filling the parameter pack:

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

Moving the parameter pack to the front of the arguments list doesn't seem to fix this either. Is there any way to achieve this perfect forwarding while keeping the optional arguments?

Minimum reproducible example on Godbolt

Aucun commentaire:

Enregistrer un commentaire