当前位置: 首页 > 知识库问答 >
问题:

不明确的重载 - 带有参数包的部分函数模板排序

储峻
2023-03-14

请考虑以下人为的代码段:

template <class... > struct pack { };

template <class R, class T, class... Args>
int foo(pack<T>, Args...)
{
    return sizeof(R);
}

template <class R, class T, class... Ts, class... Args>
int foo(pack<T, Ts...>, Args... args)
{
    return foo<T>(pack<Ts...>{}, args...);
}

int main() {
    // gcc: OK, clang: ambiguous
    foo<int>(pack<int>{});

    // gcc: ambiguous, clang: ambiguous
    foo<int>(pack<int>{}, 0);
}

如果第二个重载被更改为采用至少2种类型的包而不是至少一种类型的包时,gcc和clang都接受这两个调用:

template <class R, class T, class T2, class... Ts, class... Args>
int foo(pack<T, T2, Ts...>, Args... args)
{
    return foo<T>(pack<T2, Ts...>{}, args...);
}

如果未推导出的模板参数被移动到推导出的模板参数,则:

template <class... > struct pack { };

template <class R, class T, class... Args>
int foo(pack<R>, pack<T>, Args...)
{
    return sizeof(R);
}

template <class R, class T, class... Ts, class... Args>
int foo(pack<R>, pack<T, Ts...>, Args... args)
{
    return foo(pack<T>{}, pack<Ts...>{}, args...);
}

int main() {
    // gcc ok with both, clang rejects both as ambiguous
    foo(pack<int>{}, pack<int>{});
    foo(pack<int>{}, pack<int>{}, 0);
}

我希望每个版本的所有调用都可以。上面代码示例的预期结果是什么?

共有2个答案

柯凯旋
2023-03-14

让我们首先简化问题并考虑

template <class...> struct pack {};

template <class T>
void foo(pack<T>) {}

template <class T, class... Ts>
void foo(pack<T,Ts...>) {}

int main() {
  foo(pack<int>{});
}

clang抱怨并拒绝编译,声称void foo(pack)之间存在歧义

就目前的情况而言,我认为以下情况适用:

在平局的情况下,如果一个函数模板有尾随参数包而另一个没有,则具有省略参数的函数模板被认为比具有空参数包的函数模板更专业。

因此,似乎第一个应该是首选,铿锵是错误的。

彭令秋
2023-03-14

我现在相信,拒绝clang是正确的,而gcc接受它所接受的那些形式是不正确的。下面是一个简化的例子:

template <class...> struct pack { };

// (1)
template <class T>
void foo(pack<T> ) { }

// (2)
template <class T, class... Ts>
void foo(pack<T, Ts...> ) { }

int main() {
    foo(pack<int>{});
}

两个重载都是有效的,从(1)中推断出(2)直接成功。唯一的问题是我们能从(2)中推导出(1)。我最初认为没有...但是 [temp.deduct.type]/9 指出:

如果< code>P具有包含< code >的表单

因此,当我们合成类型时

由于演绎在两个方向上都成功,因此两个函数模板都不被认为比另一个更专业,并且调用应该是不明确的。

我还没有提交错误报告,等待社区的确认。

 类似资料:
  • 我有两个函数的重载,它们采用不同的s,当与的结果一起使用时,会导致后者的歧义问题。我不明白为什么只有这是模棱两可的。 将< code>int()与< code>bind函数一起使用时,我得到一个模糊错误 gcc-5.1错误(类似的还有clang) 然而,以下所有工作 查看构造函数 对我来说,任何在不同的类型上具有多个重载的函数都应该有歧义,但这只是绑定调用的问题。然后我想“也许有一些神奇的事情发生

  • 我希望维护语法,但似乎只能将typenames放在括号中,而不能将类放在括号中。以下是我当前的代码: 问题1:我找不到一种方法来使“default”参数对于特殊化不是必需的。我尝试了使用默认构造函数的代理类,将第三个参数更改为指针,并指定nullptr(这在语法上并不理想)和对类型的常量引用(这仍然需要用户端的三个参数),但似乎没有任何东西允许在中接受两个参数。 问题2:我找不到正确的语法来获得混

  • 假设我们有以下简单的代码: 这段代码使用clang编译并打印“T”,但使用gcc我们有以下错误: 我的问题是哪个编译器有bug,gcc还是叮当声?

  • 我试图移植一些为GCC(8.2)编写的代码以供Clang编译: GCC 8.2(和12.1)很好地编译了代码。然而,Clang 11.0.0(和14.0.0)抱怨说,从fe到feh的调用在无效feh之间不明确(Fn https://godbolt.org/z/5E9M6a5c6 哪个编译器是正确的? 如何编写这段代码以便两个编译器都接受它? 这两个和折叠表达式都可以在C 17中使用,但这是许多项目

  • 我正在努力使用一个结构的友元函数,该结构有一个模板参数,如果 和 如果尝试编译,则会出现以下链接器错误: (带有。) 我希望操作符只处理具有相同模板参数的类型,例如,foo只处理foo,而不处理foo或foo。 我认为这与这个问题密切相关,但我很难弄清楚如何解决我的问题。我尝试了许多模板定义,如

  • 考虑这对简单的函数模板。 如果我们使用非const参数调用: