简体   繁体   English

可变参数模板与使用元组在参数中添加不同的数据对

[英]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::stringstreamstd::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++14c++17 ,因此您可以使用to_stringstringstream和折叠表达式轻松实现字符串化添加行为。 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...);
}

Here's a demo .这是一个演示

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM