可变数量的(常量)引用参数

2024-06-03

我试图从我的高级代码(使用 C++11)中消除原始指针,并且我找到了引用(尤其是const)在许多情况下(当没有所有权转移时)是一个很好的替代品。

但如果有的话该怎么办variable我想通过(常量)引用传递的参数数量?

你不能创建一个std::vector or std::initializer_list引用,因为这些容器内部使用存储元素的地址,但引用没有地址。

一种可能性是使用std::vector<std::reference_wrapper<T>>但这需要笨拙的客户端代码,例如doSomething({std::ref(A()), std::ref(B()), std::ref(C())})而不是更好的doSomething({A(), B(), C()}) where A, B and C类是派生自T.罢工>

可以用其他容器吗?或者也许使用可变模板?


使用可变参数模板函数来执行此操作。当然不需要通过容器 of T到一个函数作为变量参数列表的替代T.

下面是一个 C++11 程序示例:

#include <iostream>
#include <vector>

// Base case with 0 arguments
std::vector<int> foo() {
    return std::vector<int>();
}

// General case with 1 + N arguments of type `int`.
// Return a `vector<int>` populated with the arguments. 
template<typename ...Args>
std::vector<int> foo(int const & first, Args const &... rest)
{
    std::vector<int> h(1,first);
    if (sizeof...(rest)) {
        std::vector<int> t = foo(rest...);
        h.insert(h.end(),t.begin(),t.end());
    }
    return h;

}

struct bar{};

using namespace std;

int main()
{
    int i = 1, j = 2, k = 3;

    vector<int> v0 = foo(i,j);
    vector<int> v1 = foo(i,j,k);
    cout << v0.size() << endl;
    cout << v1.size() << endl;
    // bar b;
    // vector<int> v2 = foo(i,j,k,b); <-- Compile error  
    return 0;
}

乍一看,它的定义似乎是foo一般而言 case 并不限制所有参数为(可转换为)int, 但事实上它们必须是 - 见证不可编译的初始化v2.

继续回应OP的评论

如何编写一个类型安全的函数,该函数采用任意给定的多个参数 类型,包括 const 引用类型,在 C++11 中不是一个有问题的问题。 核心语言提供了这种语法模式来执行此操作:

// Base case, 0 arguments
R Func() { [---] }

// General case, 1 + N arguments
template<typename U ...Args>
R Func(T [Modifier], Args [Modifier] ...args) {
    [---]
    if (sizeof...(args)) {
        [---Func(args)---]
    }
    [---]
}

where [---], [---Func(args)---]可以填写。

函数模板foo在上面的示例程序中应用了这种模式。 你问:What if foo 是否有比创建容器更复杂的事情?答案是:无论出现什么复杂情况,您都可以适当地应用该模式 是 - 就像您应用该模式一样:

for( [---];[---];[---]) {
    [---]
}

适当地,无论有什么并发症。可变参数函数模板 模式需要更多的习惯,因为它涉及递归模板 实例化——仅此而已。

您似乎混淆了两件事:

  • A) 接受可变数量的 T 类型参数的函数。
  • B) 一个接受 C 类型参数的函数,其中 C 是一个 T 类型对象的可迭代序列。

在你自己的回答中你说:

采用可变数量参数的函数可以写为:

void foo(std::initializer_list<rvalue_reference_wrapper<Base>> args)
{
    for (Base& arg : args)
    {
        arg.virtFunc();
        doStuffWithBaseRef(arg);
    }
}

那简直就是not一个A),它是一个B)。

在这里和您的评论中,您都表现出希望能够迭代 论点函数体内的可变参数函数。在C/C++中,有 没有机制可以迭代函数的参数(除非它是 Avarargs功能 http://en.wikipedia.org/wiki/Variadic_function#Example_in_C根据标准 C) 而你还没有发明一种。如果函数是 B) 类型,那么显然 函数可以迭代T的成员 the C这是函数的参数。 这就是你正在做的foo在你的回答中。

如果在 C++ 中不可能编写 A 类型的函数),那么作为一个拼凑 我们可以替换 B 类型的函数)。但 A) 类型的函数是 使用所示的类型安全可变参数模板模式进行常规编码,并且没有这样的拼凑 被要求。如果您想要的是 A) 类型的函数,请使用该模式 并掌握它的窍门。如果你想要的是一个迭代的函数 序列的成员T,然后像你所做的那样:写一个需要 参数是一个可迭代序列T.

被认为是一种可能的手段传递 [const] 的可迭代序列 参考对于函数,您的解决方案具有禁用限制 这些引用只能是对临时对象的引用是 在初始化列表中构造,不是对预先存在的对象的引用 - 因为它们几乎总是在真实代码中。例如,虽然 代码:

foo({Derived1(), Derived2()});

将按照预期编译并运行foo, Derived1, Derived2在你的回答中,更有可能的情况是:

Derived1 d1; // <- Comes from somewhere
Derived2 d2; // <- Comes from somewhere
foo({d1,d2}); // <- Error

不会编译,因为左值T无法绑定到T&&。出行 这个,你必须写:

Derived1 d1; // <- Comes from somewhere
Derived2 d2; // <- Comes from somewhere
foo({Derived1(d1),Derived2(d2)});

所以现在,你正在建造临时的copies“论点”,以及 一个initalizer_list of rvalue_reference_wrapper的参考文献 临时副本,以便您可以迭代对其中临时副本的引用foo.

好吧,如果你必须使用“参数”的副本,那就是多余的 费心构建一个序列对副本的引用。只是 将“参数”复制到任何合适的容器中并传递foo一个 [const] 引用 对此。这不会停止foo从迭代 [const] 引用到 容器成员就像现在一样。

看来您可能在一定程度上被这个问题所困扰:什么 将是一个合适的容器,用于容纳从多态派生的各种类型的对象 根据 B,如果不是指向动态分配对象的原始指针的容器?

对此,一个毫无争议的答案是:std::容器<std::shared_ptr<B>>, where 容器是一个标准容器模板(向量、列表等) 为您的应用程序提供适当的接口。更普遍的说法是所谓的智能指针模板,std::shared_ptr<T> (文档 http://en.cppreference.com/w/cpp/memory/shared_ptr) and std::unique_ptr<T> (文档 http://en.cppreference.com/w/cpp/memory/unique_ptr) 是标准 C++11 资源,用于避免暴露原始动态指针。

您似乎也可能被吸引std::initializer_list为了 将可迭代序列传递给函数,因为您可以轻松地 可以在使用时使用大括号初始化器构造一个。那个方便 可以保留而不处理原始动态指针or智能指针。 例如。

void foo(std::initializer_list<std::shared_ptr<Base>> args)
{
    for (auto arg : args)
    {
        arg->virtFunc();
        doStuffWithBaseRef(*arg);
    }
}

std::shared_ptr<Base> b1(new Derived1);
std::shared_ptr<Base> b2(new Derived2);
foo({b1,b2});

会好的,所以也会:

void foo(std::initializer_list<Base *> args)
{
    for (auto arg : args)
    {
        arg->virtFunc();
        doStuffWithBaseRef(*arg);
    }
}

Derived1 d1;
Derived2 d2;
foo({&d1,&d2});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

可变数量的(常量)引用参数 的相关文章

  • 预加载整个模型以估计 Tensorflow Serving 的内存消耗

    当执行预测时 Tensorflow Serving 延迟初始化模型 DAG 中的节点 这使得很难估计保存整个模型所需的内存 RAM 是否有一种标准方法可以强制 Tensorflow Serving 将模型完全初始化 加载到内存中 您可以使用
  • 在 C 中使用相等运算符 == 比较两个字符串是否相等 [重复]

    这个问题在这里已经有答案了 int main int argc argv if argv 1 hello printf True n else printf False n myProg hello False 为什么 我意识到strcmp
  • 如何正确使用memcpy?

    我有一个mainbuf bufsize 最初为空 我正在阅读一些输入 read fd otherbuf sizeof otherbuf 分配给不同的字符串otherbuf 每次我分配一个新字符串给otherbuf我想将其附加到mainbuf
  • 什么是合适的 NHibernate / Iesi.Collections.Generic.ISet 替代品?

    在最新版本的 Iesi Collections 中缺少 Iesi Collections Generic ISet 似乎有三种选择 链接哈希集 只读集 同步集 Iesi Collections Generic ReadOnlySet 似乎最
  • C++ 局部变量销毁顺序

    C 11 中是否存在局部变量释放的定义顺序 更简洁地说 同一作用域中两个局部变量的析构函数的副作用将以什么顺序变得可见 e g struct X X do something int main X x1 X x2 return 0 Is x
  • C# 中的 memcpy 函数 [重复]

    这个问题在这里已经有答案了 可能的重复 C memcpy 等效项 https stackoverflow com questions 510971 c memcpy equivalent 相当于什么memcpyC 中的函数 正如已经说过的
  • 在 UserControl C# .NET 中添加/停靠控件

    我正在编写一个 UserControl 它以编程方式添加子控件 目前我正在添加新的控件 如下所示 this Controls Add new Control Height 16 Dock DockStyle Top 我遇到的问题是新控件添加
  • CMake include_directories 和 add_subdirectories 之间的区别?

    我正在学习 CMake 来构建 C 代码 并努力解决以下概念 在我的根级目录中 我有一些 cpp 文件和 CMakeLists txt 它们在 gen cpp 目录中成功生成了一些 thrift 代码 我的根级别 CMakeLists tx
  • NHibernate 继承 - 判别器值

    NHibernate 是否可以有一个像这样工作的判别器 如果值等于 String Empty gt Class1 其他 gt Class2 我已经有一个 CultureName 字符串列 我想将其用作鉴别器 我不想添加额外的布尔列 如果 C
  • Linux 相当于 GetCommandLine 和 CommandLineToArgv?

    我想知道是否有一些 API 可以在 Linux 上获取当前进程的命令行参数 我想我是非常不清楚的 该问题的真正目的是通过命令行参数传递 unicode 文件名 从文件中读取 proc self cmdline 例如 wallyk zf od
  • 网页上的富文本编辑器

    我正在尝试在我的网页中添加一个富文本编辑器 用户可以在其中撰写评论并格式化他们所写的内容 类似于我们在此网站上撰写帖子的编辑器 谁能指出我关于此的正确方向 任何可以帮助我构建这样一个组件的教程 我还想要一个免费的产品 忘记之前提到 类似的东
  • 检测非 DPI 感知应用程序是否已扩展/虚拟化

    我正在尝试在 WinForms 应用程序中检测它是否由于操作系统具有高 DPI 而以缩放 虚拟化模式启动 目前 在以 3840x2400 缩放 200 缩放运行的系统中 应用程序将分辨率视为 1920x1200 DPI 为 96 缩放因子为
  • Microsoft Build Tools 2013 缺少 v120 目录

    我们已经安装了 Microsoft Build Tools 2013 从http www microsoft com en us download details aspx id 40760 http www microsoft com e
  • 使用 C# winforms 与 Windows 中的其他桌面应用程序交互

    我想知道是否可以与使用我的程序的其他程序进行交互 例如 单击另一个程序上的按钮等 我不确定这是否可能 但如果可能的话 有人可以提供一些 C 示例代码 Thanks 您可以创建消息并将其发送到其他进程 为此 您必须在 C 代码中使用 P In
  • 使用二维动态数组编写一个类

    我有一个家庭作业 我并不是在寻找任何人为我做这项工作 我只是在一个小方面遇到了麻烦 尽管我也接受其他方面的建议 任务是 使用二维动态数组编写一个类 构造函数传入数组的维度 构造函数还将动态数组中的所有值初始化为行索引乘以列索引 交换二维数组
  • 传递给 WCF 服务的可选查询字符串参数

    我想知道如何使用 string limit WebOperationContext Current IncomingRequest UriTemplateMatch QueryParameters Limit 在我的wcf中这个方法 Cit
  • 如何在控制台应用程序中创建事件循环/消息管道?

    我想创建一个注册了一些事件的控制台应用程序 问题是这些事件永远不会被触发 在这种特殊情况下Windows 窗体 http en wikipedia org wiki Windows Forms我应该调用的应用程序Application Ru
  • Action 的通用约束未按预期工作

    我无法理解为什么以下代码片段没有给我错误 public void SomeMethod
  • 用于 DSP 的快速 2D 卷积

    我想实现一些图像处理算法 这些算法旨在运行在小猎犬板 http en wikipedia org wiki Beagle Board 这些算法广泛使用卷积 我正在尝试为 2D 卷积找到一个好的 C 实现 可能使用快速傅里叶变换 我还希望该算
  • 使用 CRTP 模式时继承中的不明确方法

    我正在定义一个DoubleWrapper类继承自两个 CRTP 基类 Ratioable and Divable 两者都定义operator 具有不同的签名 T operator double const scalar const retu

随机推荐