如何解决省略号歧义?

时间:2017-05-05 10:01:44

标签: c++ ellipsis ambiguous

下一个代码将使用error: call of overloaded 'f(int)' is ambiguous

进行编译

当我使用一个参数调用va_list时,是否可以在不使用f的情况下解决此问题?

这是一种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;
}

1 个答案:

答案 0 :(得分:4)

你不能过度(明显地),因为它总是模棱两可的。我认为标准中的以下段落是相关的:

[over.match.viable]

  

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

     

2 首先,要成为一个可行的职能,候选职能应具备   足够多的参数可以与列表中的参数一致。

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

  •   
  • 具有少于m个参数的候选函数只有在其参数列表([dcl.fct])中有省略号时才可行。为了   重载解析的目的,任何没有的论据   相应的参数被认为是“匹配省略号”   ([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时才能实例化(从而为您提供原始函数)。现在,仅当单个参数版本不再可行时,即当存在多个参数时,才选择省略号版本。