提问人:fetis 提问时间:9/28/2023 最后编辑:UpAndAdamfetis 更新时间:9/28/2023 访问量:118
是否可以根据模板参数有条件地删除函数参数?
Can you conditionally remove a function parameter based on a template parameter?
问:
我的函数看起来像这样
template<bool extra>
void func(int& arg1, const int arg2){
//a lot of code...
if (extra && arg2 > 0) ++arg1;
arg1 *= 10;
//a lot of code...
}
问题是 when is ,不使用,但函数仍然需要指定它,从而导致不必要的内存分配(您可以在此处检查程序集输出)。有没有办法修改函数,以便在这种情况下,何时是,只需要,避免内存分配?extra
false
arg2
arg2
extra
false
arg1
arg2
答:
3赞
ChrisB
9/28/2023
#1
这类问题通常使用模板专用化来解决, 不幸的是,这通常需要一个包装结构而不是普通函数。
下面是一个示例:
template<bool extra> // default case, only used for extra == false
struct Foo
{
static void run(int arg1) {
static_assert(extra == false);
//...
}
};
template<> //specialization, used for extra == true
struct Foo<true>
{
static void run(int arg1, const int arg2) {
//...
}
};
int main(){
Foo<false>::run(1);
Foo<true>::run(2, 3);
}
根据所需的 API,您有时可以创建一个包装函数或使用来避免稍微丑陋的调用。operator()
::run
在您的特定示例中,如果两个函数版本的签名不同(因为您不希望出现这种情况),您甚至可以摆脱基本函数重载:arg2
extra == true
// In this simple case you could even remove the template argument completely
// and make the distinction purely based on the number of arguments.
// It all depends on what API you want to provide.
template<bool extra>
void func(int& arg1){
static_assert(extra == false);
}
template<bool extra>
void func(int& arg1, const int arg2){
static_assert(extra == true);
}
注意:如果模板参数应保留,则C++ 20 requires
子句或enable_if
保护而不是 s 将更准确地表达函数签名的意图,目前代价是错误消息更糟糕。static_assert
评论
1赞
fetis
9/28/2023
老实说,在这种情况下,结构模板专业化看起来很丑陋,但是函数重载是一个完美的解决方案,我不知道为什么我自己没有想出它,谢谢你这么详细的回答!
0赞
Jan Schultke
9/28/2023
如果您使用 requires-clause 而不是 static_assert,它可能会更干净。
0赞
Ben Voigt
9/28/2023
或者 SFINAE(如果您的工具链不够新,无法拥有)requires
0赞
ChrisB
9/28/2023
@JanSchultke,@BenVoigt:以下是所有三种情况的比较错误消息: godbolt.org/z/6Pjbz4s9Y 即使没有为 s 提供明确的消息,在我看来,它们已经是最具可读性的选项。过载解决总是会导致混乱的错误。吻。我知道拥有没有无效状态的函数签名感觉更好,但实际上第 1 行中的 a 之间几乎没有区别(除非我们必须防止模棱两可的重载)。因此,兼容性+可读性为我决定。static_assert
requires
static_assert
1赞
ChrisB
9/28/2023
@JanSchultke:所有三条错误消息都包含对调用站点和被调用函数的引用。但我在理论/语义层面上同意你的看法,所以我:)添加了一个注释。
评论
func(int& arg1);
func_extra(int arg1, int arg2)
// a lot of code...
void func(int &arg1, const int arg2);