由于布尔类型化模板函数中未使用的参数,如何在 C++ 中使用备用函数签名?

How to have an alternate function signature in C++, due to unused parameter in a bool typed template function?

提问人:roli 提问时间:10/25/2023 最后编辑:roli 更新时间:10/25/2023 访问量:119

问:

免责声明:这篇文章是问题,而不是通过我建议的解决方法解决的问题。

我的目标是有一个库,根据唯一的定义提供我的函数的几个实例,以避免代码冗余:increment

template <bool modify>
int increment(int a, int b) {
    if constexpr(modify)
        return a+=b;
    else
        return ++a;
}

正确实例化后,我有两种不同的实现,具体取决于 的值。modify

问题是,when 为 false,函数参数在从未使用过时仍然是必需的。modifyb

我的问题是:由于在此示例中理论上可以推导出来,因此是否可以要求编译器提供带有签名的实例化:

template int increment<false>(int a)无需自己实现(在这种情况下,函数可以保持单个实现)。increment

所以在我的库中,我可以有这样的东西:.h

template <bool modify>
int increment(int a, int b);

int increment(int a); //Which would be linked to the instance: template int increment<false>(int a)

这是一个简化的问题,我希望它能很好地说明我的问题。 我不知道 C++ 标准是否提供了这样的解决方案,或者我是否应该接近元编程扩展,或者去特定的编译器。

我知道为 分配默认值可能是一种解决方法,但这将解决这个特定示例,而我正在寻找先前提出的问题的答案。b

先谢谢你。

C++ 模板元编程 签名 编译时

评论

0赞 463035818_is_not_an_ai 10/25/2023
std::optional?无法让编译器自动生成不同的重载
0赞 463035818_is_not_an_ai 10/25/2023
还可以重命名为这两个调用,然后提供两个不同的重载incrementincrement_implementationincrementincrement_implementation
1赞 463035818_is_not_an_ai 10/25/2023
这是一个 xy 问题。有很多方法可以达到相同的效果,只是不是以你希望的方式
0赞 463035818_is_not_an_ai 10/25/2023
这个问题尚不清楚。在 if 的两个分支中已经有两个单独的实现。您可以使用两个单独的重载,而不是使用。我知道这是一个简化的示例,但您的示例并不能说明您尝试解决的实际问题constexpr if
0赞 chrysante 10/25/2023
“我的函数增量必须有一个单一的实现”——你能解释一下为什么吗?从调用方的角度来看,通常有一个模板还是两个重载并不重要。我其次,这闻起来像 xy 问题。

答:

3赞 Ted Lyngmo 10/25/2023 #1

下面是具有单个实现的函数模板:

template <bool modify, class... Args>
int increment(Args... args) {
    return modder<modify>(args...).res;
}

modder另一方面,是一个具有专用化的类,因为函数模板不能被专门化为具有不同的参数列表,但类模板可以:

template <bool>
struct modder {        // the primary template will match the `true` case
    modder(int a, int b) : res(a + b) {}
    int res;
};

template <>
struct modder<false> { // specialization for the `false` case
    modder(int a) : res(a + 1) {}
    int res;
}

Red.Wave 的好答案的启发,这里有另一个版本,需要 1 个参数 if is 和 2 个参数 if is:modifyfalsemodifytrue

template <bool modify, class... Args>
    requires(sizeof...(Args) == modify + 1)
int increment(Args... args) {
    if constexpr (sizeof...(Args) == 1) {
        // just return the single argument + 1
        return (..., (args + 1));
    } else {
        // return the sum of the two arguments
        return (... + args);
    }
}

评论

1赞 M.M 10/25/2023
为了解释第一个解决方案的基本原理 -- 函数模板不能专门用于具有不同的参数列表,但类模板可以专门用于具有完全相同名称的完全不同的成员函数
0赞 Ted Lyngmo 10/25/2023
@M.M,我把它添加到答案中,以使其更清楚。谢谢!
0赞 Red.Wave 10/25/2023
我喜欢它,但巫毒教水平有点高。减少对库的依赖是一个加分项,OTH。我只是想知道为什么该函数需要 2 个标记来表示参数数量(标志 + 参数)?bool
0赞 Ted Lyngmo 10/25/2023
@Red.Wave“巫毒级别” - :-)我正在考虑一个参数版本。不确定这是否有帮助 - “为什么函数需要 2 个标记” - 我不确定模板参数的来源(它可能来自上面的某些级别),并且因为应该只取一个参数并且应该让它只取两个参数,这就是我所追求的。return (..., ++args);modifyfalseincrementtrue
1赞 Red.Wave 10/25/2023
我也是一个巫师。我能读懂你的咒语,但我想它让一些人眼花缭乱。
2赞 Red.Wave 10/25/2023 #2

我不会挑战你的设计。我只是删除了显式模板参数:

auto next(auto x auto ...y)
requires (sizeof...(y)<2)
{
    if constexpr (sizeof...(y))
       return x + get<0>(std::tie(y...));
    else
       return x + 1;
};

auto x=next(7,8);
auto y=next(x);

对于这种特殊情况,我也可以使用默认参数值获得类似的结果:

int next(int a, int b=1){ return a+b; };

但我想这将是对你不想分享的更复杂问题的过度简化。