在 return 类型的函数模板中使用 decltype 消除了由于异常规范引起的错误

Usage of decltype in return type of function template removes error due to exception specification

我看到了一个问题的答案 。答案的作者在那里利用了

exception specifications do not participate1 in template argument deduction.

在上面链接的答案中解释了以下内容无法编译的原因:

#include <iostream>

template<typename T>
void timer(T a) noexcept(func(T()))
{
    std::cout<<"template timer called"<<std::endl;
}

void timer(...)
{
    std::cout<<"ordinary timer called"<<std::endl;   
}
int main()
{
    timer(5);//won't compile
    return 0;
}

因为异常规范不参与TAD,重载决议选择函数模板版本,所以当稍后实例化异常规范时,程序格式错误,我们得到错误。

现在我修改了上面的程序,看看我是否理解正确。特别是,我添加了 decltype(func(T())) 作为函数模板版本的 return 类型(如下所示),然后错误消失了:

template<typename T>
decltype(func(T())) timer(T a) noexcept(func(T())) //return type added here
{
    std::cout<<"template timer called"<<std::endl;
    return func(T());//return statement added here
}

void timer(...)
{
    std::cout<<"ordinary timer called"<<std::endl;   
}
int main()
{
    timer(5); //works now? 
    return 0;
}

我的问题是,为什么当我们将 return 类型添加到函数模板中时,如上所示,错误消失了?

PS:我的问题不是第一个例子为什么报错,而是修改后的例子不报错的原因。


1此引自C++ Templates: The Complete Guide.

这里由于没有func,所以在函数模板return类型中替换模板实参时,我们得到 substitution failure 并且由于 SFINAE 这个函数模板没有添加到集合中。也就是说,忽略了.

因此调用 timer(5); 使用普通函数 timer 因为它是现在函数模板已被忽略的唯一可行选项。因此程序编译并给出输出:

ordinary timer called