你可以在不使用数组的情况下将不同数量的相同类型的参数传递给函数吗?

时间:2018-05-20 21:57:24

标签: c++ parameters overloading

我需要从一个最小值传递到一个函数最多七个文件路径。有一种惯例,只有文件路径足以识别如何处理每个文件。

参数顺序无关紧要。

处理此问题的明显选项(我当前实现的选项)是将空字符串作为未使用插槽的参数传递。

另一个是将参数作为数组或向量传递。

另一个是实现所有可能的参数排列(可能,不实用)。

我想知道是否有办法简单地指定参数的数量可以变化,然后只是简单地传递参数。

因此,假设只有一个f()实现,使用特殊语法来表示不同数量的参数

以下所有内容都应编译:

int main()
{
   f(file);
   f(file1, file2);
   f(file1, file3, file2, file6);
}

有没有办法在C ++中实现这个目标?

3 个答案:

答案 0 :(得分:4)

您可以使用递归模板功能。

something ? doThis : orDoThis

答案 1 :(得分:3)

如果你真的需要一个变量(无界限)参数

否则,如果您有固定数量的(可选)参数

  • 如果您使用 C ++ 20或更高版本

  • 如果您使用 C ++ 03或更高版本

    • 使用可空/可选类型(例如原始指针,boost::optional,C ++ 17的std::optional ...) - 请参阅@NicolBolas的回答。

      < / LI>
    • 定义所有必需/逻辑重载(可能使用自定义类型) - 丑陋,但这可以通过外部代码生成器和/或预处理器自动完成。

否则,如果您可以使用不同的设计来完成相同的操作,则可以执行以下任一操作 - 对于 C ++ 03及更高版本:< / p>

  • 按照@PaulMcKenzie的建议将指针传递给struct

  • 设计一个允许设置属性的类(通过构造函数和/或方法),然后使用成员函数对该数据执行操作,例如:

    ShaderCompiler sc(vs, fs, ...);
    sc.setGeometryShader(...);
    sc.compile();
    
  • 一种特别好的方式(参见例如QString)是设计一个允许这样做的类:

    result = ShaderCompiler()
        .vertex(...)
        .fragment(...)
        ...
        .compile()
    ;
    
  • 同样,利用argument-dependent lookup

    Shader()
        << Vertex(...)
        << Fragment(...)
        ...
    ;
    

答案 2 :(得分:0)

由于你有一套有限的可能性,这是处理这个问题的明显方法:

using opt_path = std::optional<path>;

shader compile_shaders(opt_path vs, opt_path tcs = std::nullopt, opt_path tes = std::nullopt, opt_path gs = std::nullopt, opt_path fs = std::nullopt, opt_path cs = std::nullopt)
{
  ...
}

这些只是对所有其他着色器路径使用默认参数。您可以通过std::optional的界面告知哪些是提供的,哪些不是。如果您没有使用C ++ 17,那么您显然会将其替换为boost::optional或类似类型。

当然,无论你处理这个问题,都会导致界面明显不佳。考虑一下为了创建最常见的情况需要做什么:顶点着色器结合片段着色器:

compile_shaders(vs_path, std::nullopt, std::nullopt, std::nullopt, fs_path);

用户会记住它们之间有3个阶段吗?赔率很高,他们不会。人们将经常犯错只使用2 std::nullopt或使用4.并且考虑到VS + FS是最常见的情况,你有一个界面,最常见的情况是非常容易出错。

现在可以肯定,您可以重新排列参数的顺序,使FS成为第二个参数。但是如果你想使用其他阶段,你现在必须查找函数的定义以记住哪些值映射到哪些阶段。至少,我在这里做的方式遵循OpenGL的管道。任意映射都需要查找文档。

如果你想创建一个计算着色器,你必须记住有6个阶段你必须明确地为空:

compile_shaders(std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, cs_path);

将所有这些与更具自我描述性的界面进行比较:

shader_paths paths(vs_path, shader_paths::vs);
paths.fragment(fs_path);
auto shader = compile_shaders(paths);

这里没有歧义。使用第二个参数明确声明给构造函数的路径是顶点着色器。因此,如果您需要计算着色器,则可以使用shader_paths::cs来表达它。然后使用适当命名的函数为路径提供片段着色器。接下来,编译着色器,然后就完成了。