为什么 enable_if_t 需要数据类型标识符和默认值?

Why enable_if_t needs to have datatype identifier and a default value?

我无法理解下面代码段中的 2 条注释代码行与它们前面的代码行有何不同?有没有一种简单的方法来理解注释行的含义与它们前面的行的含义?我无法在脑海中说出如何阅读注释行及其旁边的行。谁能解释一下?请不要指点我文档。我在那里度过了一段时间,但我仍然不清楚,否则我不会在这里发布这个问题。

#include <iostream>
#include <type_traits>

//template<class T, std::enable_if_t<std::is_integral_v<T>, bool>>
template<class T, std::enable_if_t<std::is_integral_v<T>, bool> K = true>
void fun(T value)
{
    std::cout << "\n In Integral version";
}

//template<class T, std::enable_if_t<std::is_floating_point_v<T>, bool>>
template<class T, std::enable_if_t<std::is_floating_point_v<T>, bool> K = true>
void fun(T value)
{
    std::cout << "\n In Floating point version";
}

int main()
{    
    fun(4);
    fun(4.4);
}

当我使用注释代码时显示以下错误,我不知道它们是什么意思或上面的代码如何解决它们。

Error(s):
2044199993/source.cpp: In function ‘int main()’:
2044199993/source.cpp:22:10: error: no matching function for call to ‘fun(int)’
     fun(4);
          ^
2044199993/source.cpp:8:6: note: candidate: template<class T, typename std::enable_if<is_integral_v<T>, bool>::type <anonymous> > void fun(T)
 void fun(T value)
      ^~~
2044199993/source.cpp:8:6: note:   template argument deduction/substitution failed:
2044199993/source.cpp:22:10: note:   couldn't deduce template parameter ‘<anonymous>’
     fun(4);
          ^
2044199993/source.cpp:15:6: note: candidate: template<class T, typename std::enable_if<is_floating_point_v<T>, bool>::type <anonymous> > void fun(T)
 void fun(T value)
      ^~~
2044199993/source.cpp:15:6: note:   template argument deduction/substitution failed:
2044199993/source.cpp:22:10: note:   couldn't deduce template parameter ‘<anonymous>’
     fun(4);
          ^
2044199993/source.cpp:23:12: error: no matching function for call to ‘fun(double)’
     fun(4.4);
            ^
2044199993/source.cpp:8:6: note: candidate: template<class T, typename std::enable_if<is_integral_v<T>, bool>::type <anonymous> > void fun(T)
 void fun(T value)
      ^~~
2044199993/source.cpp:8:6: note:   template argument deduction/substitution failed:
2044199993/source.cpp:23:12: note:   couldn't deduce template parameter ‘<anonymous>’
     fun(4.4);
            ^
2044199993/source.cpp:15:6: note: candidate: template<class T, typename std::enable_if<is_floating_point_v<T>, bool>::type <anonymous> > void fun(T)
 void fun(T value)
      ^~~
2044199993/source.cpp:15:6: note:   template argument deduction/substitution failed:
2044199993/source.cpp:23:12: note:   couldn't deduce template parameter ‘<anonymous>’
     fun(4.4);
            ^

以下内容本身就完全没问题:

template<class T, std::enable_if_t<std::is_integral_v<T>, bool>>
void fun(T value)
{
    std::cout << "\n In Integral version";
}

template<class T, std::enable_if_t<std::is_floating_point_v<T>, bool>>
void fun(T value)
{
    std::cout << "\n In Floating point version";
}

它的模板有两个模板参数。当你想打电话给他们时,问题就出现了。如果您尝试像在 main:

中那样调用它们
int main()
{    
    fun(4);
    fun(4.4);
}

您将收到以下错误:

<source>:18:5: error: no matching function for call to 'fun'
    fun(4);
    ^~~
<source>:5:6: note: candidate template ignored: couldn't infer template argument ''
void fun(T value)
     ^
<source>:11:6: note: candidate template ignored: couldn't infer template argument ''
void fun(T value)
     ^
<source>:19:5: error: no matching function for call to 'fun'
    fun(4.4);
    ^~~
<source>:5:6: note: candidate template ignored: couldn't infer template argument ''
void fun(T value)
     ^
<source>:11:6: note: candidate template ignored: couldn't infer template argument ''
void fun(T value)
     ^

模板有 2 个模板参数。一个是 T,另一个是 bool 或替换失败。第二个参数不能从函数参数中推导出来,因此出错。

考虑在 T==int 的情况下你会得到什么。 std::enable_if_t 只是一个别名。在您的情况下,对于 bool 或未定义别名:

template<int, bool>  // because int is integral
void fun(T value)
{
    std::cout << "\n In Integral version";
}

template<int, "substitution failure"> // because int is integral
void fun(T value)
{
    std::cout << "\n In Floating point version";
}

第二个是替换失败,因此重载解析选择第一个。它有两个模板参数。

第二个模板参数除了在条件为 false 时失败之外没有任何用途。您不希望用户调用

 fun<int,true>(42);

您希望呼叫者通过

呼叫它
 fun(42);

因为明确指定 tempalte 参数会破坏 SFINAE 的全部目的。在无法推导出模板参数的情况下不要求调用者指定模板参数的方法是提供默认值。那就是 K = trueK = false 也可以。由于您不必为参数命名,因此以下内容也适用:

template<class T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
void fun(T value)
{
    std::cout << "\n In Integral version";
}

template<class T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
void fun(T value)
{
    std::cout << "\n In Floating point version";
}