我需要从一个最小值传递到一个函数最多七个文件路径。有一种惯例,只有文件路径足以识别如何处理每个文件。
参数顺序无关紧要。
处理此问题的明显选项(我当前实现的选项)是将空字符串作为未使用插槽的参数传递。
另一个是将参数作为数组或向量传递。
另一个是实现所有可能的参数排列(可能,不实用)。
我想知道是否有办法简单地指定参数的数量可以变化,然后只是简单地传递参数。
因此,假设只有一个f()实现,使用特殊语法来表示不同数量的参数
以下所有内容都应编译:
int main()
{
f(file);
f(file1, file2);
f(file1, file3, file2, file6);
}
有没有办法在C ++中实现这个目标?
答案 0 :(得分:4)
您可以使用递归模板功能。
something ? doThis : orDoThis
答案 1 :(得分:3)
如果你真的需要一个变量(无界限)参数:
如果您使用 C ++ 11或更高版本:
使用std::initializer_list
(仅当所有类型相同时) - 请参阅https://stackoverflow.com/a/16338804/9305398。
使用variadic templates(即参数包) - 请参阅@ super的答案和/或https://stackoverflow.com/a/16338804/9305398。
如果您使用 C ++ 03或更高版本:
否则,如果您有固定数量的(可选)参数:
如果您使用 C ++ 20或更高版本:
如果您使用 C ++ 03或更高版本:
使用可空/可选类型(例如原始指针,boost::optional
,C ++ 17的std::optional
...) - 请参阅@NicolBolas的回答。
定义所有必需/逻辑重载(可能使用自定义类型) - 丑陋,但这可以通过外部代码生成器和/或预处理器自动完成。
否则,如果您可以使用不同的设计来完成相同的操作,则可以执行以下任一操作 - 对于 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
来表达它。然后使用适当命名的函数为路径提供片段着色器。接下来,编译着色器,然后就完成了。