将调用链接到 C++ 中的临时变量

发布于 2024-12-07 05:43:08 字数 1594 浏览 1 评论 0原文

我有一个对字符串进行转换的类,就像这样

class transer{
    transer * parent;
protected:
    virtual string inner(const string & s) = 0;
public:
    string trans(const string & s) {
        if (parent) 
            return parent->trans(inner(s));
        else 
            return inner(s);
    }
    transer(transer * p) : parent(p) {}

    template <class T>
    T create() { return T(this); }
    template <class T, class A1>   // no variadic templates for me
    T create(A1 && a1) { return T(this, std::forward(a1)); }
};

我可以创建一个子类

class add_count : public transer{
    int count;
    add_count& operator=(const add_count &);
protected:
    virtual string inner(const string & s) { 
        return std::to_string((long long)count++) + s; 
    }
public:
    add_count(transer * p = 0) : transer(p), count(0) {}
};

然后我可以使用转换:

void use_transformation(transer & t){
    t.trans("string1");
    t.trans("string2");
}
void use_transformation(transer && t){
    use_trasnformation(t);
}

use_transformation(add_count().create<add_count>());

是否有更好的设计?如果可以的话,我想避免使用动态分配/shared_ptr,但我不确定临时对象是否会在整个调用过程中保持活动状态。我还希望能够让每个 Transer 在销毁期间能够与其父级通信,因此临时对象也需要按正确的顺序销毁。创建链式转换并将其保存以供以后使用也很困难,因为

sometrans t = add_count().create<trans1>().create<trans2>().create<trans3>();

会保存指向不再存在的临时变量的指针。做类似的事情

trans1 t1;
trans2 t2(&t1);
trans3 t3(&t2);

很安全,但很烦人。有没有更好的方法来进行此类连锁操作?

I have a class that does a transformation on a string, like so

class transer{
    transer * parent;
protected:
    virtual string inner(const string & s) = 0;
public:
    string trans(const string & s) {
        if (parent) 
            return parent->trans(inner(s));
        else 
            return inner(s);
    }
    transer(transer * p) : parent(p) {}

    template <class T>
    T create() { return T(this); }
    template <class T, class A1>   // no variadic templates for me
    T create(A1 && a1) { return T(this, std::forward(a1)); }
};

So I can create a subclass

class add_count : public transer{
    int count;
    add_count& operator=(const add_count &);
protected:
    virtual string inner(const string & s) { 
        return std::to_string((long long)count++) + s; 
    }
public:
    add_count(transer * p = 0) : transer(p), count(0) {}
};

And then I can use the transformations:

void use_transformation(transer & t){
    t.trans("string1");
    t.trans("string2");
}
void use_transformation(transer && t){
    use_trasnformation(t);
}

use_transformation(add_count().create<add_count>());

Is there a better design for this? I'd like to avoid using dynamic allocation/shared_ptr if I can, but I'm not sure if the temporaries will stay alive throughout the call. I also want to be able to have each transer be able to talk to its parent during destruction, so the temporaries also need to be destroyed in the right order. It's also difficult to create a chained transformation and save it for later, since

sometrans t = add_count().create<trans1>().create<trans2>().create<trans3>();

would save pointers to temporaries that no longer exist. Doing something like

trans1 t1;
trans2 t2(&t1);
trans3 t3(&t2);

would be safe, but annoying. Is there a better way to do these kinds of chained operations?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

简单爱 2024-12-14 05:43:08

临时变量将在完整表达式结束时被销毁
与它们的构造顺序相反。小心后者,
但是,由于无法保证顺序
评估。 (当然,直接依赖除外:如果你
需要一个临时的来创建下一个——如果我已经
如果理解正确,那就是你的情况——那么你就安全了。)

Temporaries will be destructed at the end of the full expression, in the
reverse order they were constructed. Be careful about the latter,
however, since there are no guarantees with regards to the order of
evaluation. (Except, of course, that of direct dependencies: if you
need one temporary in order to create the next—and if I've
understood correctly, that's your case—then you're safe.)

初心 2024-12-14 05:43:08

如果您不想动态分配,则可以将操作的数据传递给启动链的函数,或者您需要一个根类型来保存它(除非您想要过度复制)。示例(可能无法编译):

struct fooRef;  
struct foo  
{  
fooRef create() { return fooRef( m_Val ); }  
   foo& operator=( const fooRef& a_Other );  
   std::string m_Val;  
}  
struct fooRef  
{  
   fooRef( std::string& a_Val ) : m_Val( a_Val ) {}  
   fooRef create() { return fooRef( m_Val ); }  
   std::string& m_Val;  
}  
foo& foo::operator=( const fooRef& a_Other ) { m_Val = a_Other.m_Val; }  
foo startChain()  
{  
    return foo();  
}  
foo expr = startChain().create().create(); // etc

首先,字符串位于从 startChain() 创建的临时 foo 上,所有链式操作都对该源数据进行操作。然后赋值最后将值复制到指定的 var 中。您几乎可以保证 startChain() 上的 RVO。

If you don't want dynamic allocation you either pass the data which is operated on to the function that initiates the chain, or you need a root type which holds it for you ( unless you want excessive copying ). Example ( might not compile ):

struct fooRef;  
struct foo  
{  
fooRef create() { return fooRef( m_Val ); }  
   foo& operator=( const fooRef& a_Other );  
   std::string m_Val;  
}  
struct fooRef  
{  
   fooRef( std::string& a_Val ) : m_Val( a_Val ) {}  
   fooRef create() { return fooRef( m_Val ); }  
   std::string& m_Val;  
}  
foo& foo::operator=( const fooRef& a_Other ) { m_Val = a_Other.m_Val; }  
foo startChain()  
{  
    return foo();  
}  
foo expr = startChain().create().create(); // etc

First the string lies on the temporary foo created from startChain(), all the chained operations operates on that source data. The assignment then at last copies the value over to the named var. You can probably almost guarantee RVO on startChain().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文