【问题标题】:Overloaded function template disambiguation with `std::enable_if` and non-deduced context使用 `std::enable_if` 和非推导上下文的重载函数模板消歧
【发布时间】:2017-05-28 20:04:22
【问题描述】:

考虑以下代码:

template <typename T>
struct dependent_type
{
    using type = T;
};

template <typename T>
auto foo(T) -> std::enable_if_t<std::is_same<T, int>{}>
{
    std::cout << "a\n"; 
}

template<typename T> 
void foo(typename dependent_type<T>::type) 
{
    std::cout << "b\n";
}
  • foo 的第一个重载可以从其调用中推断出T

  • foo 的第二个重载是 non-deduced context

int main()
{    
    foo<int>( 1 );      // prints "b"
    foo<double>( 1.0 ); // prints "b"
    foo( 1 );           // prints "a"
}

为什么foo&lt;int&gt;( 1 ) 打印的是“b”而不是“a”?

wandbox example

【问题讨论】:

  • 我猜答案是“b 更专业,所以如果可能的话总是被调用”,原因可能在某个地方 here(它从页面的中间开始)。不过这对我来说有点多。
  • 确实是个好问题。谢谢你。 +1
  • 下次,我建议将代码发布为单个 sn-p,以便人们可以复制/粘贴一次,而不必复制/粘贴两次才能尝试您的代码(并且要么具有正确的包含指令,要么以不同的方式演示所选重载)。
  • @JohannesSchaub-litb:只需点击“魔杖盒示例”?
  • 我不知道那个链接去哪里了。一开始我什至没有发现它。我想对于不熟悉“在线编译器”概念的用户来说,它一定像“我的壁纸收藏”链接一样令人困惑。

标签: c++ templates c++14 language-lawyer overload-resolution


【解决方案1】:

从本质上讲,部分排序规则表明 dependent_type 重载更加专业化,因为没有推断出上下文。

排序模板函数的过程是基于转换模板函数类型并依次对每个模板进行模板推导,从第一个模板(取T的那个)到第二个(取dependent_type的那个),然后从第二个到第一个。

规则过于复杂,无法在此处复制,但如果您想了解血腥细节,请阅读[temp.func.order] 及其链接的段落。这是一个快速的简化:

对于模板函数的每个模板参数,组成一个唯一的类型并将参数替换为该类型。此示例的转换类型为:

void foo(UniqueType); //ignoring the SFINAE for simplicity
void foo(typename dependent_type<UniqueType>::type); 

然后我们从两个方向执行模板推导:一次使用第一个模板的参数作为第二个模板的参数,一次使用第二个模板的参数作为第一个模板的参数。这类似于对这些函数调用执行推论:

//performed against template <class T> void foo(typename dependent_type<T>::type);
foo(UniqueType{});                     

//performed against template <class T> void foo(T);        
foo(dependent_type<UniqueType>::type{});

在执行这些推论时,我们试图辨别一个重载是否比另一个更专业。当我们尝试第一个时,演绎失败,因为typename dependent_type&lt;T&gt;::type 是一个非演绎的上下文。第二种推演成功,因为dependent_type&lt;UniqueType&gt;::type就是UniqueType,所以T推演成UniqueType

由于从第二个模板到第一个模板的演绎失败,因此第二个模板被认为比第一个模板更专业。最终结果是重载决议更喜欢foo&lt;int&gt;(1)的第二个模板。

【讨论】:

  • 您能否详细说明“转换” 的含义以及使用术语“第一个模板”时所指的含义 i> 和“第二个模板”?我知道规则很复杂,但如果我不得不说实话,你的回答根本不会提高我对这种情况的理解。
  • @VittorioRomeo 解释得很好here。当dependent_type&lt;UniqueType&gt;::type{}作为参数时,编译器可以推导出T,但是当UniqueType{}被传递时,它不能从typename dependent_type&lt;T&gt;::type推导出T,所以结论是b更特化跨度>
  • @VittorioRomeo 我试着解释一下,有帮助吗?
  • @TartanLlama:是的,您的回答和 Piotr 的链接都非常有帮助。我现在明白了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-01
  • 1970-01-01
相关资源
最近更新 更多