gpt4 book ai didi

C++11:保证来自模板参数的非转换引用

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:31:03 24 4
gpt4 key购买 nike

所以我有一个结构 X:

struct X
{
int typecode;
char* pData;
int length;
...
}

和一长串类型,我们称这个集合为 TS。 TS 包括大多数原始类型和几个类类型。

对于 TS 中的每个类型 T,我都定义了一个常规函数:

void setup(X& x, const T& t);

例如 T = string 设置如下:

void setup(X& x, const string& s)
{
x.typecode = X_STRING;
x.pData = s.c_str();
x.length = s.size();
...
}

现在我有一个模板函数 convert_to_x:

template<class T>
X convert_to_x(const T& t)
{
X x;
memset(x, 0, sizeof(x));
setup(x, t);
return x;
}

还有一个接受 X 数组的函数 f:

void f(X* xs, int num_args);

还有一个可变参数模板函数g:

template<class... Args)
void g(Args... args)
{
constexpr num_args = sizeof...(args);

X xs[] = { convert_to_x(args)... };

f(xs, num_args);
}

发生的事情是,您可以使用任意数量的参数和类型调用 g,它会将参数转换为 X 类型的数组,然后调用 f。

问题是如果调用 g 时使用的类型不在 TS 中,但可以转换为 TS 中的类型,则会发生以下情况:

  1. 调用转换构造函数来创建临时 t。
  2. setup 将存储指向此临时文件的指针。
  3. 临时元素被销毁。
  4. 使用包含悬挂指针的 xs 调用 f。

我需要一种进入 g 的方法来转换任何可转换为 TS 中的类型但不是 TS 中的类型的参数,并在 的整个范围内保留它们>g.

实现此目标的最佳方法是什么?

更新:

我刚刚想到的一种可行方法是为 TS 中的每个类型 T 定义一个常规函数 convert,如下所示:

T convert(const T& t) { return t; }

然后为g定义一个包装器:

template<class... Args>
void g2(Args... args)
{
g(convert(args)...);
}

但我认为这会导致对 TS 中已有且不需要转换的类型进行不必要的复制。有没有什么方法可以使用右值/左值语义来避免这种情况?

更新 2:

也许这行得通:

对于 TS 中的每个 T:

const T& convert(const T& t) { return t; }
T convert(const T&& t) { return t; }

然后:

template<class... Args>
void g2(Args... args)
{
g(convert(args)...);
}

在任何情况下安装程序可能会收到带有上述内容的临时文件?

最佳答案

您可以为 setup 添加已删除的重载:

void setup(X& x, const string& s) = delete;

由于右值引用比 const 左值引用更容易绑定(bind)到临时对象,因此调用带有临时对象的 setup 将选择带有右值引用的重载。但是由于这个 setup 重载被删​​除了,实际调用它是非法的。因此,当使用错误类型的参数调用 g 时,行 X xs[] = { convert_to_x(args)... }; 需要 convert_to_args 调用已删除的 setup 版本,因此实例化失败。反过来,它也会导致 g 的特定实例化也失败。

编辑

查看您的更新#2,这应该可行。由于 convert 已经导致到 TS 之一的最佳转换,因此永远不应使用不需要的类型调用 g。因此,在调用 setup 时,不需要的转换不会创建临时文件。因此,任何临时对象都将成为 g 的参数,并保证在 g 的持续时间内存在。

编辑2

你是对的 T convert(const T&& t) { return t; } 可能导致值被不必要地复制。但这很容易解决:

const T& convert(const T& t) { return t; }
const T&& convert(const T&& t) { return std::move(t); }

您不会得到任何值的复制。临时对象的生命周期也是正确的,因为临时对象一直存在到创建它们的完整表达式结束为止:

template<class... Args>
void g2(Args... args)
{
g(convert(args)...);
} // ^^^^ temporaries created by a conversion here will live until g returns

关于C++11:保证来自模板参数的非转换引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12031394/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com