尽管使用了模板方法,但SFINAE不起作用

SFINAE not working although template methods are used

本文关键字:SFINAE 不起作用 模板方法      更新时间:2023-10-16

考虑以下代码,这些代码试图使用SFINAE根据模板参数提供不同的方法实现。

#include <type_traits>
#include <iostream>
template<bool S>
struct C{
     template<typename std::enable_if<!S>::type* = nullptr>
     int foo(int i){
         return i + 1;
      }
     template<typename std::enable_if<S>::type* = nullptr>
     int foo(int i){
        return i;
     }
};
int main(){
     C<true> c1;
     C<false> c2;
     std::cout << c1.foo(0) << c2.foo(0) << std::endl;
}

这个例子的灵感来源于std::enable_if的参考页面。如您所见,结构体C<S>有两个foo方法。如果Strue,则应启用一个,如果Sfalse,则应禁用另一个。但是,该代码不会编译,但会引发以下错误:

src/test.cpp: In instantiation of ‘struct C<true>’:
src/test.cpp:19:12:   required from here
src/test.cpp:7:8: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
    int foo(int i){
        ^
src/test.cpp: In instantiation of ‘struct C<false>’:
src/test.cpp:20:13:   required from here
src/test.cpp:12:8: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
    int foo(int i){

因此,编译器似乎完全忽略了SFINAE,并在发现类型未启用时引发错误。我在这里做错了什么?

S不是方法的模板参数,它是类的模板参数。在类的实例化过程中,S已经确定,因此,std::enable_if<!S_>::type不再依赖于类型,因此不能以您使用它的方式使用。正如Nawaz所回答的,您可以通过使用重载来解决这个问题,但您也可以将S作为方法的模板参数——有点像:

#include <type_traits>
#include <iostream>
template<bool S>
struct C {
  template<bool S_ = S, typename std::enable_if<!S_>::type* = nullptr>
  int foo(int i){
    return i + 1;
  }
  template<bool S_ = S, typename std::enable_if<S_>::type* = nullptr>
  int foo(int i) {
    return i;
  }
};
int main(){
  C<true> c1;
  C<false> c2;
  std::cout << c1.foo(0) << c2.foo(0) << std::endl;
}
  template<typename std::enable_if<!S>::type* = nullptr>
  int foo(int i)
  {
     return i + 1;
  }

这不是函数模板,因为这个(假定(函数模板没有模板参数。它甚至不起作用。代码只是格式不正确。

请注意,S封闭类模板的模板参数,而不是函数(template(以下代码是正确的(但不能解决您的问题(:

  template<typename SS, typename std::enable_if<!SS>::type* = nullptr>
  int foo(int i)
  {
     //etc
  }

这里typename SS定义了函数模板的模板参数。您的函数没有这样做。std::enable_if中使用的模板参数必须是相同函数模板的模板参数。


使用函数重载来解决您的问题:

template<bool S>
struct C
{
    int foo(int i)
    {
       return foo_impl(std::integral_constant<bool, S>(), i);
    }
private:
     int foo_impl(std::true_type, int i)
     {
         return i + 1;
     }
     int foo_impl(std::false_type, int i)
     {
        return i;
     }
};

这就是一般性的执行。但在这种特定情况下,当您使用bool作为模板参数时,另一种解决方案可能是:

template<bool S>
struct C
{
    int foo(int i)
    {
       return S ? foo_a(i) : foo_b(i);
    }
private:
     int foo_a(int i)
     {
         return i + 1;
     }
     int foo_b(int i)
     {
        return i;
     }
};

由于S是编译器已知的,所以我相信编译器会消除return S ? foo_a(i) : foo_b(i);中的分支,而是根据S的值编写return foo_a(i);return foo_b(i);,从而有效地生成更快的代码。