可变参数模板:如何“展望未来”在论据中
我正在实现一个 printf 版本,它也可以处理 std::string 参数。 它的核心有以下功能:
// use sprintf to transform the single format string with the value t
template<typename T>
std::string simpleFormat(const std::string sFormat, const T t) {
size_t required = snprintf(NULL, 0, sFormat.c_str(), t);
char sTemp[required+1];
sprintf(sTemp, sFormat.c_str(), t);
return std::string(sTemp);
}
// termination of recursion
std::string recursiveFormat(stringvec &vParts, stringvec &vFormats, uint i) {
return vParts[i];
}
// recursively walk through arguments
template<typename T, typename... Args>
std::string recursiveFormat(stringvec &vParts, stringvec &vFormats, uint i, T value, Args... args) {
std::string sRes = "";
if (i < vFormats.size()) {
sRes += vParts[i];
sRes += simpleFormat(vFormats[i], value);
sRes += recursiveFormat(vParts, vFormats, i+1, args...);
}
return sRes;
}
这非常有效。但是,要处理带有星号的格式字符串,例如在 printf("%0*d", width, value)
中,这种方法不起作用。
我尝试添加两个函数
// get the next argument and return it
template<typename U, typename... Args>
U fetchNextParam(const U value2, Args... args) {
return value2;
}
// handle the star by providing sprintf with two values
template<typename T, typename U>
std::string starFormat(const std::string sFormat, const T value1, const U value2) {
size_t required = snprintf(NULL, 0, sFormat.c_str(), value1, value2);
char sTemp[required+1];
sprintf(sTemp, sFormat.c_str(), value1, value2);
return std::string(sTemp);
}
并修改 recursiveFormat()
函数,如下所示:
template<typename T, typename... Args>
std::string recursiveFormat(stringvec &vParts, stringvec &vFormats, uint i, T value, Args... args) {
std::string sRes = "";
if (i < vFormats.size()) {
sRes += vParts[i];
//--- trying to handle star
if (vFormats[i].find('*') != std::string::npos) {
auto value2 = fetchNextParam(args...);
sRes += starFormat(vFormats[i], value, value2);
} else {
sRes += simpleFormat(vFormats[i], value);
}
sRes += recursiveFormat(vParts, vFormats, i+1, args...);
}
return sRes;
}
但是,此代码无法编译:我收到编译器消息:
sptest.cpp: In instantiation of ‘std::string recursiveFormat(stringvec&, stringvec&, uint, T, Args ...) [with T = double; Args = {}; std::string = std::__cxx11::basic_string<char>; stringvec = std::vector<std::__cxx11::basic_string<char> >; uint = unsigned int]’:
sptest.cpp:114:32: recursively required from ‘std::string recursiveFormat(stringvec&, stringvec&, uint, T, Args ...) [with T = int; Args = {double}; std::string = std::__cxx11::basic_string<char>; stringvec = std::vector<std::__cxx11::basic_string<char> >; uint = unsigned int]’
sptest.cpp:114:32: required from ‘std::string recursiveFormat(stringvec&, stringvec&, uint, T, Args ...) [with T = int; Args = {int, double}; std::string = std::__cxx11::basic_string<char>; stringvec = std::vector<std::__cxx11::basic_string<char> >; uint = unsigned int]’
sptest.cpp:124:36: required from here
sptest.cpp:107:41: error: no matching function for call to ‘fetchNextParam()’
107 | auto value2 = fetchNextParam(args...);
| ~~~~~~~~~~~~~~^~~~~~~~~
sptest.cpp:58:3: note: candidate: ‘template<class U, class ... Args> U fetchNextParam(U, Args ...)’
58 | U fetchNextParam(const U value2, Args... args) {
| ^~~~~~~~~~~~~~
sptest.cpp:58:3: note: template argument deduction/substitution failed:
sptest.cpp:107:41: note: candidate expects at least 1 argument, 0 provided
107 | auto value2 = fetchNextParam(args...);
| ~~~~~~~~~~~~~~^~~~~~~~~
我必须做什么才能使功能看起来“一个”在可变参数中“领先”?
I am implementing a printf
version which can also handle std::string
arguments.
At the heart of it there are these functions:
// use sprintf to transform the single format string with the value t
template<typename T>
std::string simpleFormat(const std::string sFormat, const T t) {
size_t required = snprintf(NULL, 0, sFormat.c_str(), t);
char sTemp[required+1];
sprintf(sTemp, sFormat.c_str(), t);
return std::string(sTemp);
}
// termination of recursion
std::string recursiveFormat(stringvec &vParts, stringvec &vFormats, uint i) {
return vParts[i];
}
// recursively walk through arguments
template<typename T, typename... Args>
std::string recursiveFormat(stringvec &vParts, stringvec &vFormats, uint i, T value, Args... args) {
std::string sRes = "";
if (i < vFormats.size()) {
sRes += vParts[i];
sRes += simpleFormat(vFormats[i], value);
sRes += recursiveFormat(vParts, vFormats, i+1, args...);
}
return sRes;
}
This works very well. However, to handle a format strings with an asterisk, like for instance in printf("%0*d", width, value)
this approach doesn't work.
I tried by adding two functions
// get the next argument and return it
template<typename U, typename... Args>
U fetchNextParam(const U value2, Args... args) {
return value2;
}
// handle the star by providing sprintf with two values
template<typename T, typename U>
std::string starFormat(const std::string sFormat, const T value1, const U value2) {
size_t required = snprintf(NULL, 0, sFormat.c_str(), value1, value2);
char sTemp[required+1];
sprintf(sTemp, sFormat.c_str(), value1, value2);
return std::string(sTemp);
}
and modify the recursiveFormat()
function like this:
template<typename T, typename... Args>
std::string recursiveFormat(stringvec &vParts, stringvec &vFormats, uint i, T value, Args... args) {
std::string sRes = "";
if (i < vFormats.size()) {
sRes += vParts[i];
//--- trying to handle star
if (vFormats[i].find('*') != std::string::npos) {
auto value2 = fetchNextParam(args...);
sRes += starFormat(vFormats[i], value, value2);
} else {
sRes += simpleFormat(vFormats[i], value);
}
sRes += recursiveFormat(vParts, vFormats, i+1, args...);
}
return sRes;
}
However, this code won't compile: i get the compiler message:
sptest.cpp: In instantiation of ‘std::string recursiveFormat(stringvec&, stringvec&, uint, T, Args ...) [with T = double; Args = {}; std::string = std::__cxx11::basic_string<char>; stringvec = std::vector<std::__cxx11::basic_string<char> >; uint = unsigned int]’:
sptest.cpp:114:32: recursively required from ‘std::string recursiveFormat(stringvec&, stringvec&, uint, T, Args ...) [with T = int; Args = {double}; std::string = std::__cxx11::basic_string<char>; stringvec = std::vector<std::__cxx11::basic_string<char> >; uint = unsigned int]’
sptest.cpp:114:32: required from ‘std::string recursiveFormat(stringvec&, stringvec&, uint, T, Args ...) [with T = int; Args = {int, double}; std::string = std::__cxx11::basic_string<char>; stringvec = std::vector<std::__cxx11::basic_string<char> >; uint = unsigned int]’
sptest.cpp:124:36: required from here
sptest.cpp:107:41: error: no matching function for call to ‘fetchNextParam()’
107 | auto value2 = fetchNextParam(args...);
| ~~~~~~~~~~~~~~^~~~~~~~~
sptest.cpp:58:3: note: candidate: ‘template<class U, class ... Args> U fetchNextParam(U, Args ...)’
58 | U fetchNextParam(const U value2, Args... args) {
| ^~~~~~~~~~~~~~
sptest.cpp:58:3: note: template argument deduction/substitution failed:
sptest.cpp:107:41: note: candidate expects at least 1 argument, 0 provided
107 | auto value2 = fetchNextParam(args...);
| ~~~~~~~~~~~~~~^~~~~~~~~
What must i do to get the functionality to look "one ahead" in the variadic arguments?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您还可以提供
fetchNextParam(/*空参数*/)
You can also provide
fetchNextParam(/*empty parameter*/)
仅当有足够的参数时,您才可以使用
if constexpr
(C++17) 来激活代码:You might use
if constexpr
(C++17) to activate code only if there is enough parameter: