【问题标题】:How can I resolve ellipsis ambiguity?如何解决省略号歧义?
【发布时间】:2017-10-03 18:21:23
【问题描述】:

接下来的代码将使用error: call of overloaded 'f(int)' is ambiguous进行编译

当我用一个参数调用f 时,我可以不使用va_list 来解决这个问题吗?


这是一个 printf 类型的函数。我只是想知道是否可以在不引入新名称的情况下单独处理简单案例来提高效率。

有什么解决办法吗?

#include <cstdarg>

void f(int n, ...) {
    va_list args;
    va_start(args, n);
    //Do something
    va_end(args);
}

void f(int n) {
    //Do something without va_list
}

int main() {
    f(42);
    return 0;
}

【问题讨论】:

  • 为什么你觉得你需要用省略号开头?它是 C++ 中通常使用的最后一种工具。
  • 这是一个 printf 类型的函数。我只是想知道是否可以在不引入新名称的情况下单独处理简单案例来提高效率。
  • 如果你在 c++ 中做 printf 风格的事情,也许考虑 variadic templates

标签: c++ ellipsis ambiguous


【解决方案1】:

你不能有这样的重载(很明显),因为它总是模棱两可的。我认为标准中的以下段落是相关的:

[over.match.viable]

1 来自为给定上下文构建的候选函数集 ([over.match.funcs]),选择一组可行的函数,从中选择 通过比较参数转换将选择最佳函数 最适合的序列([over.match.best])。的选择 可行函数考虑参数之间的关系和 转换序列排序以外的函数参数。

2 首先,作为一个可行的函数,一个候选函数应该有 足够的参数数量与列表中的参数一致。

  • 如果列表中有 m 个参数,则所有具有恰好 m 个参数的候选函数都是可行的。

  • 仅当参数列表 ([dcl.fct]) 中有省略号时,具有少于 m 个参数的候选函数才是可行的。为了 重载决议的目的,任何不存在的论点 相应的参数被认为是“匹配省略号” ([over.ics.ellipsis]) .

  • 仅当 (m+1)-st 参数具有默认参数时,具有多于 m 个参数的候选函数才是可行的。130 重载决议,参数列表在右边被截断,所以 正好有 m 个参数。

所以这两个重载都是可以调用的可行函数。现在编译器必须根据您提供的参数的转换序列来确定哪个是更好的候选者。而且它们在这方面都同样出色,在任何一种情况下都不需要转换 42。


一个可能的解决方案

让我们利用其他重载规则。在重载决议中生成和找到的模板函数被认为是比非模板函数更小的匹配。因此,让我们将省略号版本作为模板:

#include <iostream>
#include <type_traits>
#include <cstdarg>

void vf(int n, std::va_arg args) {
    //Do something with args
}

template<typename T>
auto f(T n, ...)
  -> std::enable_if_t<std::is_same<T, int>::value> {
  std::va_list args;
  va_start(args, n);
  vf(n, args);
  va_end(args);
}

void f(int n) {
    //Do something without va_list
}

int main() {
    f(42);
    f(42, 53);
    return 0;
}

但我们会将 SFINAE 应用于返回类型,因此它只能在 T 为 int 时实例化(从而为您提供原始函数)。现在,仅当单参数版本不再可行时,即当有多个参数时,才选择省略号版本。

【讨论】:

  • 我建议突出显示“一种可能的解决方案”(如标题行),这是有趣的部分,并且更具可读性。
猜你喜欢
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 2016-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多