gpt4 book ai didi

c++ - 使用默认函数模板参数的意外重载决议

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:44:53 26 4
gpt4 key购买 nike

我遇到了一个似乎非常出乎意料的重载解析行为。以下代码被 gcc 和 clang 拒绝并出现歧义错误:

template <typename T>
struct A
{
typedef T key_type;
};

template <typename T>
void foo(A<T> rng, T val);

template <typename T, typename U = T>
void foo(T, typename U::key_type);

int main()
{
A<int> i;
foo(i, 0);
}

错误是:

test.cpp:16:5: error: call to 'foo' is ambiguous
foo(i, 0);
^~~
test.cpp:8:6: note: candidate function [with T = int]
void foo(A<T> rng, T val);
^
test.cpp:11:6: note: candidate function [with T = A<int>, U = A<int>]
void foo(T, typename U::key_type);
^

我希望两者完全匹配,但第一个重载在部分排序中获胜,因为在第一个参数中 A<T>T 更专业.

令我震惊的是,如果我将第二个签名更改为:

template <typename T, typename U = T>
void foo(T, typename T::key_type);

gcc 和 clang 现在都接受代码,并选择我最初期望的第一个重载。

我看不出这种变化如何影响行为:我所做的只是用默认值 ( U ) 替换既未明确指定也未推导的模板参数 ( T ) .

话又说回来,更改前的行为从一开始就出乎意料,所以也许我遗漏了什么。

谁能解释一下:

  1. 为什么第一种情况不明确;和
  2. 为什么我所做的更改解决了歧义?

如果相关,我测试的编译器版本是 gcc 4.8.0 和最近的 clang 主干构建。

最佳答案

问题是在参数推导之后是否存在将推导的模板参数替换到参数列表中的阶段。此阶段是默认参数将用于尚未推导的模板参数的地方。

关于这个额外步骤完成了哪些推导上下文以及没有完成什么的问题是一个活跃的核心问题,http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#697 .

如果执行额外的替换步骤,则还需要实例化模板(否则替换步骤本身就没有多大意义)。您也可以只选择默认参数,而不进行替换,但在标准中,这两者是结合在一起的,所以作为一个实现者,我不会选择那条路。

部分排序在很大程度上独立于执行部分排序的上下文(考虑了一些依赖于上下文的事情——例如,忽略没有显式调用参数的函数参数)。它也独立于模板参数是否传递了显式模板参数(因此,如果您给 U 赋值,偏序将不会“记住”它。

Clang 和 GCC 不执行替换步骤,也不使用模板默认参数。因此,当将 TU::key_type 进行比较以找出 U 时,他们会说“嗯,一个非推导的上下文。我们将说“成功,没有什么不匹配的!”对于这个参数”。将 TT::key_type 进行比较时也会发生同样的情况。当它比较另一个方向时,WhatEver::key_typeTT 也可以推断出依赖类型。因此,对于第二个参数,在您的两次尝试中,两个模板至少彼此一样专业。

但重要的区别在于,推导后,参数类型列表中使用的所有参数必须有值。

In most cases, all template parameters must have values in order for deduction to succeed, but for partial ordering purposes a template parameter may remain without a value provided it is not used in the types being used for partial ordering. [ Note: A template parameter used in a non-deduced context is considered used. — end note ]

在你的第二次尝试中,T 是由第一个参数推导出来的,所以在完成参数/参数类型的比较之后没有发生任何不好的事情。在第一次尝试中,U 未被推导,因此第一个模板在之后并不被认为比第二个模板“更专业”。

关于c++ - 使用默认函数模板参数的意外重载决议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15697067/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com