0

这个令人遗憾的冗长示例是我正在尝试编写的一段真实代码的精简版。它有两个问题。首先,正如所写,它不能编译:错误是

error: cannot bind ‘std::string’ lvalue to ‘std::string&&’
error:   initializing argument 3 of ‘void pack_arg(datum*, size_t, std::string&&)’

并且由对 的调用触发shut_the_door&&如果我在 的相关重载中取出pack_arg,那么它会编译,但生成的代码似乎不必要地复制了两个字符串。其次,我需要确保数组d持有指针的所有临时字符串在调用vprocess. 现在,生成的代码似乎在调用之前就破坏了它们。

只要我有机会process通过可重载的函数调用运行每个参数,我愿意考虑对数组的填充方式进行相当彻底的更改,而独立于所有其他此类参数。(特别是,我怀疑如果我可以在联合中使用临时初始化引用的特殊规则会使问题 2 消失std::string&,但由于datum数组的每个成员都是通过赋值而不是初始化填充的,所以目前不会工作,我不知道如何通过初始化填充它而不会丢失对 的调用pack_arg,这在更大的上下文中是必要的。)

编辑:使用std::forwardbetween pack_argsandpack_arg似乎没有帮助;我得到完全相同的错误消息。

#include <string>
#include <stddef.h>
using std::string;

union datum
{
  const string* s;
  int i;
};

inline void
pack_arg(datum* d, size_t n, int t)
{
  d[n].i = t;
}

inline void
pack_arg(datum* d, size_t n, string && t)
{
  d[n].s = &t;
}

inline void
pack_args(datum*, size_t)
{
}

template <typename X, typename... XS> inline void
pack_args(datum* d, ::size_t n, X&& x, XS&&... xs)
{
  pack_arg(d, n, x);
  pack_args(d, n+1, xs...);
}

extern void vprocess(datum*, size_t);

template <typename... XS> inline void
process(XS&&... xs)
{
  size_t n = sizeof...(xs);
  datum d[n];
  pack_args(d, 0, xs...);
  vprocess(d, n);
}

extern string shut_the_door();

void
demo()
{
  process(1, 2, "buckle my shoe", 3, 4, shut_the_door());
}
4

1 回答 1

0

Luc 带来了一个非常有趣的观点(我简要浏览了代码,只阅读了签名):

如果您要将指向 的指针存储std::string在容器中,那么您的代码必须确保参数不是右值,因为这将在函数调用完成后留下一个悬空指针。

我对你的代码思考得越多,我就越相信整个事情只是一个坏主意。如果没有每个元素是什么的标签,您就无法知道数组的哪个元素是什么类型。对象的生命周期将很难维护(std::string特别是对于 s ......)也许你应该重新考虑设计。


您遇到了新的 C++11 语法的一个有趣的怪癖。这两个声明中的双与号 ( &&) 的含义并不相同:

inline void
pack_arg(datum* d, size_t n, string && t);         // [1]
template <typename X, typename... XS> inline void
pack_args(datum* d, ::size_t n, X&& x, XS&&... xs) // [2]

在 [1] 中,类型参数string&&将仅绑定到允许区分临时(或std::moved 对象)和左值的右值。右值引用的行为类似于函数内部的左值。在 [2] 中,因为您在模板中并且X是推断类型,所以应用了一组不同的规则,X&&并将根据参数解析为左值引用或右值引用。

在您的情况下,参数实际上是临时的,因此X&&将被映射到std::string&&,但在函数内部它被视为左值,无法绑定。您可以通过添加来解决此问题std::forward

template <typename X, typename... XS> inline void
pack_args(datum* d, ::size_t n, X&& x, XS&&... xs)
{
  pack_arg(d, n, std::forward(x));
  pack_args(d, n+1, std::forward(xs)...);
}

模板将std::forward根据参数本身是左值还是右值引用来生成左值或右值引用。

于 2012-09-27T22:03:01.900 回答