[英]variadic templates vs using tuples for adding different data pairs in an argument
following main code works fine以下主要代码工作正常
string hello = "Hello ";
string world = "templates!";
cout << "var template add: ";
cout << setprecision(2) <<
var_template_add(5, 4, 5.5, 4.0);
for following template generator code and variadic func用于以下模板生成器代码和可变参数函数
template <typename T>
auto add(T a, T b) {
return a + b;
}
template <typename T, typename... Rest>
auto var_template_add(T first, T second, Rest... others) {
return first + second + add (others...);
}
But if added two more string args, like this但是如果再添加两个字符串参数,就像这样
var_template_add(5, 4, 5.5, 4.0, hello, world);
is caught by compiler error saying "no matching overloaded function found".被编译器错误捕获,说“没有找到匹配的重载 function”。
Again,再次,
string hello = "Hello ";
string world = "templates!";
cout << "strings add result: " << setprecision(2) << add(hello, world) << endl;
could work if i write template function "add" like below:如果我编写模板 function “添加”,如下所示:
template <typename T1, typename T2>
auto add(T1 a, T2 b) {
return a + b;
}
My question is, how could i make the line我的问题是,我怎样才能做到这一点
var_template_add(5, 4, 5.5, 4.0, hello, world);
work without writing another add function like just above?!无需编写另一个添加 function 就像上面一样工作?!
please note i could use tuple to pass this values but for now, i just want to keep away.请注意,我可以使用元组来传递这些值,但现在,我只想远离。 any thoughts/improvements?有什么想法/改进吗?
Adding std::string
to integral values will not work unless you choose to make your function explicitly convert to string, such as using a std::stringstream
or std::to_string
.除非您选择将 function 显式转换为字符串,例如使用std::stringstream
或std::to_string
,否则将std::string
添加到整数值将不起作用。
If you want this to behave correctly with stringizing behavior, you will need to change it to do some form of explicitly string building.如果您希望它在字符串化行为中正确运行,则需要对其进行更改以进行某种形式的显式字符串构建。
However, you can at least make your current var_template_add
work with any number of arguments, since the current definition requires 4 arguments or it will not work.但是,您至少可以使您当前的var_template_add
与任意数量的 arguments 一起使用,因为当前定义需要 4 个 arguments 否则它将不起作用。 This will allow the var_template_add(hello, world)
example to work.这将允许var_template_add(hello, world)
示例工作。
In C++11 this can be done by using some template recursion.在 C++11 中,这可以通过使用一些模板递归来完成。 This doesn't require adding any new functions per-se -- just renaming an existing one and altering one.这本身不需要添加任何新功能——只需重命名现有功能并更改一个。
The idea is to recursively call the var_template_add
until you end up with 2 arguments, and then just add the two together:这个想法是递归调用var_template_add
直到你最终得到 2 个 arguments,然后将两者相加:
// rename'add' to 'var_template_add'. Use this as recursive base-case.
template <typename T, typename U>
auto var_template_add(T first, U second)
-> decltype(first + second)
{
return first + second;
}
// adds first argument and delegates 'second' and 'others...' to the next 'var_template_add'
template <typename T, typename U, typename... Rest>
auto var_template_add(T first, U second, Rest... others)
-> decltype(first + var_template_add(second, others...))
{
return first + var_template_add(second, others...);
}
For 2 arguments, it will call the first overload.对于 2 个 arguments,它将调用第一个重载。 For 3 or more arguments, it will call the second, which will recursively call into the next var_template_add
, until eventually calling into the first.对于 3 个或更多 arguments,它将调用第二个,后者将递归调用下一个var_template_add
,直到最终调用第一个。
Note: This answer is because the question is tagged C++11 -- but please be aware that your use of auto
return types without a trailing return type is actually C++14 and not C++11.注意:这个答案是因为问题被标记为 C++11 - 但请注意,您使用没有尾随返回类型的auto
返回类型实际上是 C++14 而不是 Z657433F6E7DAA506474F81184BFA6
If you have C++17, you can do this even easier using variadic fold expressions:如果您有 C++17,则可以使用可变折叠表达式更轻松地完成此操作:
template <typename T, typename U, typename...Rest>
auto var_template_add(T first, U second, Rest...others)
{
return first + second + (... + others);
}
Edit:编辑:
Since OP updated the tags to include c++14
and c++17
, you can achieve the stringizing add behavior quite easily using either to_string
or stringstream
and a fold expression.由于 OP 更新了标签以包含c++14
和c++17
,因此您可以使用to_string
或stringstream
和折叠表达式轻松实现字符串化添加行为。 For this, I do recommend a different function though -- since appending string sequences is semantically quite a different operation from "adding" values.为此,我确实建议使用不同的 function - 因为附加字符串序列在语义上与“添加”值完全不同。
The best approach would probably be to use std::stringstream
, something like:最好的方法可能是使用std::stringstream
,例如:
template <typename...Args>
std::string variadic_add_str(Args&&...args)
{
auto stream = std::string_stream{};
stream << (... << std::forward<Args>(args));
return stream.str();
}
The only way for the current call to work is for var_template_add
to return a single type, so it would need to be a string.当前调用起作用的唯一方法是var_template_add
返回单个类型,因此它需要是一个字符串。
Instead, you could write the cout
inside the function, so then you only need:相反,您可以在 function 中编写cout
,因此您只需要:
template <typename T, typename... Rest>
auto var_template_add(T first, T second, Rest... others) {
cout << setprecision(2) << (first + second) << " ";
if constexpr (sizeof...(others)) var_template_add(others...);
}
Note that there is no if constexpr
pre c++17, so in that case, having an extra overload as base case is a good option.请注意,没有if constexpr
pre c++17,因此在这种情况下,将额外的重载作为基本情况是一个不错的选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.