【问题标题】:Best way to send multiple arguments of different types to a method for processing. c++将多个不同类型的参数发送到一个方法进行处理的最佳方式。 C++
【发布时间】:2017-06-23 18:35:49
【问题描述】:

目前我有一个方法如下:

std::stringstream ss; ss << "lives:" << this->Lives;
Text->RenderText(ss.str(), font, x, y, scale,color);

现在这对我来说似乎很乱,我想将它减少到一行。 但我似乎想不出一种干净利落的方法。

我曾想过使用可变函数,但这将我限制为一种类型,并且我必须指定参数的数量。

虽然使用了 std::initializer_list 或可变模板,但它似乎并没有更好。

在这个解决方案中:Here Georg Fritzsche 提供的答案显示了一个可能的解决方案:

helper() << a << b << c;

但它的实际实现我....不确定。

类似于:

Text->render(font, x, y, scale,color) << "lives:" << this->Lives;

会很好,但在方法中我不确定如何定义它。

我无法返回一个字符串流对象,因为返回后我无法访问它。

那么像这样的链式

【问题讨论】:

  • Text-&gt;RenderText("lives:" + std::to_string(this-&gt;Lives), font, x, y, scale,color); ?
  • @Jarod42 你不能把+ 放到char const * 上。您可以使用 ""s C++11 operator"" 使其成为 std::string,但:` "lives: "s + ... other stuff`
  • @xaxxon:如果右边的参数是std::string,你可以,就像在 Jarod42 的例子中一样。
  • @BenjaminLindley 我发誓我过去尝试这样做时遇到过错误,但我只是尝试过,它当然可以工作。谢谢。

标签: c++


【解决方案1】:

返回一个累积字符串所有部分的临时对象,然后当它在语句末尾自动销毁时,让它在其析构函数中呈现内容。

#include <utility>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;

class Renderer {
    stringstream sstream;
    float x;
    float y;
public:
    Renderer(float x, float y) : x(x), y(y){}
    template<class T>
    Renderer && operator<<(T&& t) {
        sstream << std::forward<T>(t);
        return std::move(*this);
    };
    ~Renderer() {
        // your real code replaces the line below..
        cout << sstream.str() << endl;
    }
};

Renderer render(float x, float y) {
    return Renderer(x, y);
}

int main() {
    int i = 5;
    render() << "foo" << i;
}

直播:https://wandbox.org/permlink/UToweQELJ4jt0QYl

【讨论】:

  • Renderer::operator&lt;&lt; 作为模板方法可能更有用:template &lt;typename T&gt; Renderer &amp;&amp; operator&lt;&lt;(T&amp;&amp; x) { sstream &lt;&lt; std::forward&lt;T&gt;(x); return std::move(*this); };
  • 啊,好吧,所以有一个中间类。我试试看。
  • 应该添加#include &lt;utility&gt; 以确保std::forward 可用。
  • 这让我想知道,这个对象什么时候会失去作用域?什么时候调用解构函数?是在处理线之后吗?还是在使用函数的末尾?
  • @StevenVenham 它位于行尾(语句),除非它被扩展:en.cppreference.com/w/cpp/language/lifetime - 临时对象生命周期部分这对于 C++ 定义得很好。
【解决方案2】:

我将如何处理这个问题

好的,所以你有这个:

std::stringstream ss; ss << "lives:" << this->Lives;
Text->RenderText(ss.str(), font, x, y, scale,color);

现在,如果您真的想在一行中完成,为什么不将字符串生成放入单个函数调用中,具体的类似

std::string life_text(int lifecount){
   std::stringstream ss;
   ss<<"lives:"<<lifecount;
   return ss.str();
}

所以你可以这样调用渲染:

Text->render(life_text(lives), x, y, scale,color);

你在找什么

首先,在我回答您提出的问题之前,&lt;&lt; 运算符并不意味着方法链接。至少在原版 C++ 中没有,事实上,我不认为它在 C++ 中的任何地方都使用过。

流对象并不是真正链接一个方法,而是调用类似的东西

template<typename T> std::stringstream& operator<<(std::stringstream& rightside,T leftside){
    rightside.append(leftside);
    return rightside;
}

因此,每一步都会发生如下情况:

stringstream r;
r<<"lives:";
r<<this->lives;

您所要求的并不是那么简单。您需要更改 rendertext 函数以返回一种可以传递参数的新对象。这很难。

其次,这意味着您的评估顺序会使这更具挑战性。有办法解决这个问题,但我不知道这是否是一个像上面这样简单的便利功能不会更好的情况。

如果您一心想这样做,那么您可能不得不做一些可能非常有问题的事情。您必须让对象调用实际的渲染函数(我假设您可能从某个框架中获得)。

很好,但是现在您需要添加一些范围,如果您需要按特定顺序完成此操作,这可能很重要。它可能看起来像这样:

{
    Text->render(x,y,scale,color)<<"lives:"<<this->Lives;
}

在我看来,这看起来令人沮丧。

如果您愿意,我会回答您可能对我的回答提出的任何问题,但是,至少在我看来,您最初的目标似乎是您按照自己的喜好找错了方向这样做。

以您想要的方式接近解决方案

template<std::function<typename ReturnType(std::string&,typename Ts...)> Func>
class caller{
std::stringstream r;
Ts... arguments;
Func storedFunction;
public:

caller(Func x,typename Ts...):storedFunction(x){
arguments=Ts;

}
~caller(){
Func(r.str(),...Ts);
}
friend template<typename S,typename P> caller<S>& operator<<(caller<S>&,T value);
};
template<typename S,typename P> caller<S>& operator<<(caller<S>& c, T value){
    c.r<<value;
}

调用者 a_suitable_name(std::bind(&Text::Render,&Text),_those_other_arguments); 来电者

这不太可能以目前的形式工作,但我没有时间完成定义。

【讨论】:

  • 我告诉过你,你不明白 &lt;&lt; 运算符在做什么。您想做的事情并不容易完成,并且可能需要大量时间才能正常工作。
  • 我花了大约 3 分钟来写下我的答案。
  • 这比编写那个函数要多,不是吗?我只是指出,像这样的简单、简短的函数可能更适合这里的特定情况。我在回答中指出了一个问题,还是您认为排序对渲染不重要?
  • 您正在谈论的“排序”问题..您是说您认为临时变量可能不会在正确的时间被销毁吗?除非显式延长其生命周期,否则该变量将在行尾销毁。 en.cppreference.com/w/cpp/language/lifetime
  • 老实说,我没有考虑过使用临时变量。虽然我不同意我没有回答这个问题,但我回答了,甚至在尝试使用损坏的模板代码之前,我建议以一种方式做。虽然我承认你的观点,但请你不要以那种方式使用吓人的引号。
猜你喜欢
  • 2016-05-09
  • 2013-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
相关资源
最近更新 更多