转发使用非类型模板参数声明函数模板

时间:2018-03-21 03:34:31

标签: c++ function templates c++17 sfinae

鉴于以下计划

#include <type_traits>
#include <utility>

template <typename T, typename std::enable_if_t<std::is_same<std::decay_t<T>, int>::value>*>
void foo(T&&);
template <typename T, typename std::enable_if_t<std::is_same<std::decay_t<T>, int>::value>* = nullptr>
void foo(T&&) {}

int main() {
    foo(int{});
}

https://wandbox.org/permlink/rlASqofr0Is38lop

Clang很好地编译了这段代码(https://wandbox.org/permlink/xCfDNvTlYD2x7WG3),但是gcc给出了一个错误,说它无法推断出匿名模板参数。谁是对的?

我查看了函数模板部分[temp.fct]中的标准,发现了类似的内容。有一个关于哪个函数模板是首选的部分,我们有两个相同的函数模板,具有不同的名称查找 - 匿名非类型模板参数是否构成“依赖名称”?这是标准中的相关文字

  

为了确定两个相关名称(17.6.2)是否相同,只考虑名称本身,而不是模板上下文中的名称查找结果。如果同一函数模板的多个声明在此名称查找的结果中不同,则使用第一个声明的结果。

template <class T> decltype(g(T())) h();
int g(int);
template <class T> decltype(g(T())) h()
  { return g(T()); }
int i = h<int>();

鉴于上面示例中的两个相同的函数模板,如果第一个是首选的,那么在我的情况下这同样适用吗?在我的案例中,名称查找在哪里?这是否意味着铿锵有误?

为什么这个程序会编译 - https://wandbox.org/permlink/I0tcHTPvGMWbdpC3?这是因为这里考虑了第一个名字,在完成模板推导后我们调用了相同函数模板的定义吗?

1 个答案:

答案 0 :(得分:1)

我认为Clang在这里是正确的。

来自[temp.param / 10]:

  

可以使用的默认模板参数集合由。获得   合并来自所有先前声明的默认参数   模板的方式与默认函数参数相同(11.3.6)。 [   实施例

template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;
     

相当于

template<class T1 = int, class T2 = int> class A;
     

- 结束示例]

在您的示例中,您有两个模板foo的声明(请参阅[temp / 1]),因此它们应相当于:

template <typename T, typename std::enable_if_t<std::is_same<std::decay_t<T>, int>::value>* = nullptr>
void foo(T&&) {}