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

使用“std::enable\u if”和非推断上下文消除重载函数模板歧义

桑坚成
2023-03-14

考虑以下代码:

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的第二个重载是一个非推断上下文。

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

为什么foo

wandbox示例


共有1个答案

申屠乐池
2023-03-14

从本质上讲,部分排序规则说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{});

在执行这些推导时,我们试图辨别一个重载是否比另一个更专业。当我们尝试第一个时,推导失败,因为typenamedependent_type

由于从第二个模板到第一个模板的扣除失败,因此第二个模板被视为比第一个模板更专业化。最终的结果是重载解析更倾向于第二个模板

 类似资料:
  • 我发现了和类型推导的以下行为,这对我来说是意想不到的: 中的两行都会导致错误: 没有函数模板“stdfunc_test”的实例与参数列表匹配 尝试在Visual Studio 2015中编译时。 为什么类型演绎不从函数类型中演绎模板类型,有没有变通方法?

  • 多亏了C11,我们收到了系列的仿函数包装器。不幸的是,我一直只听到关于这些新添加的不好的消息。最受欢迎的是它们非常慢。我测试了它,与模板相比,它们真的很糟糕。 111毫秒对1241毫秒。我认为这是因为模板可以很好地内联,而通过虚拟调用覆盖内部。 显然,在我看来,模板也有其问题: 它们必须以头的形式提供,这不是您在以封闭代码形式发布库时可能不希望做的事情, 因此,我可以假设s可以用作传递函子的事实标

  • 模板函数与重载是密切相关的。从函数模板产生的相关函数都是同名的,因此编译器用重载的解决方法调用相应函数。 函数模板本身可以用多种方式重载。我们可以提供其他函数模板,指定不同参数的相同函数名。例如,图12.2的printArray函数模板可以用另一printArray函数模板重载,用参数lowSubscriPt和highSubscript指定要打印的数组部分(见练习12.4)。 函数模板也可以用其他

  • 我试图移植一些为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中使用,但这是许多项目

  • 考虑下面粘贴的代码。我定义了一个非常简单的类,编译器为其生成一个隐式推导指南,这样就可以在没有显式模板参数的情况下构造它。但是,模板参数推导不适用于从仅直接转发到目标类的简单别名模板构造对象: 正如您从上面的代码注释中看到的,g给了我一个关于使用别名模板而没有模板参数的错误。我希望在这样的例子中,模板参数推导会被转发。 所以,我的问题是:这是通过明示设计目前的措辞来对班级模板的论点进行演绎的建议吗

  • 我试图编写一个通用的obj工厂,使用可变模板调用各种类的构造函数。代码如下: 在大多数例子中,变量arg总是这样写“Args” 错误:没有可行的转换从'__bind( 在移除“ 但我不知道为什么?