通过跳过可选参数来填充参数包
Filling a parameter pack by skipping optional arguments
我正在编写一个用于记录目的的辅助函数:它收集调用站点
信息,同时还创建了一个 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");
将参数包移动到参数列表的前面似乎没有解决
这要么。有什么办法可以实现这种完美的转发,同时保持
可选参数?
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");
查看额外内容 ()
。可选参数进入 ()
,转发的参数进入第二组 ()
。
你也可以让 makeError
成为 class
并给它一个 operator()
来产生实际错误,并为它的 ctor 提供默认参数。然后你会得到:
auto err = makeError<FileError>{}("foo.exe", "Invalid header");
哪个可能不那么令人困惑,或者更令人困惑。其中之一。
我正在编写一个用于记录目的的辅助函数:它收集调用站点
信息,同时还创建了一个 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");
将参数包移动到参数列表的前面似乎没有解决 这要么。有什么办法可以实现这种完美的转发,同时保持 可选参数?
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");
查看额外内容 ()
。可选参数进入 ()
,转发的参数进入第二组 ()
。
你也可以让 makeError
成为 class
并给它一个 operator()
来产生实际错误,并为它的 ctor 提供默认参数。然后你会得到:
auto err = makeError<FileError>{}("foo.exe", "Invalid header");
哪个可能不那么令人困惑,或者更令人困惑。其中之一。