尝试在 C++ 中使用 std::enable_if 有条件地定义成员函数时编译程序失败

Failed to compile program when trying to define member function conditionally using std::enable_if in C++

提问人:mk_g_d 提问时间:7/19/2023 最后编辑:JeJomk_g_d 更新时间:7/19/2023 访问量:27

问:

我像往常一样编写一个带有一些成员函数的简单类,这次我尝试仅在类的模板参数满足某些条件时定义成员函数,但代码似乎无法在 g++ 和 vs2019 中编译。最简单的演示是这样的:

#include <type_traits>

template <int RowCnt, int ColCnt, typename ValueType = double>
class Matrix {
public:
  template <std::enable_if_t<RowCnt == ColCnt, int> = 0>
  void GetInverseMatrix() {}

private:
  ValueType data[RowCnt][ColCnt];
};

int main() {
  Matrix<3, 3> a;
  Matrix<3, 5> b; // Compilation would fail here
  return 0;
}

g++ 的错误输出如下所示:

test_enable_if_valid.cc: In instantiation of ‘class Matrix<3, 5>’:
test_enable_if_valid.cc:15:16:   required from here
test_enable_if_valid.cc:7:8: error: no type named ‘type’ in ‘struct std::enable_if<false, int>’
    7 |   void GetInverseMatrix() {}
      |

虽然 vs2019 讲述了类似的事情:

1>D:\labs\enable_if_test_1\main.cpp(7,1): error C2938: 'std::enable_if_t<false,int>' : Failed to specialize alias template
1>D:\labs\enable_if_test_1\main.cpp(6,17): message : see reference to alias template instantiation 'std::enable_if_t<false,int>' being compiled
1>D:\labs\enable_if_test_1\main.cpp(15,15): message : see reference to class template instantiation 'Matrix<3,5,double>' being compiled

在我看来,编译器本可以跳过函数的编译,因为没有调用,或者除非 SFINA 规则应该起作用。你能告诉我为什么我错了,或者为什么编译器的行为与我上面的期望不同吗?GetInverseMatrix()Matrix<3, 5>::GetInverseMatrix()

提前感谢您,任何信息将不胜感激!

C++ 模板 C++17 SFINAE 类模板

评论


答:

2赞 n. m. could be an AI 7/19/2023 #1

SFINAE 在将显式指定或推导的模板参数替换为模板参数时起作用

函数模板有一个模板参数,参数本身是无效的,除非 ,甚至在发生任何替换之前。GetInverseMatrixRowCnt == ColCnt

模板参数的有效性可能取决于同一模板的前面的模板参数,因此可以:

template <int a, std::enable_if_t<a==42, int> = 0>
void foo() {}

但这是不行的:

template <int a>
struct bar
{
   template <std::enable_if_t<a==42, int> = 0>
   void foo() {}
};
bar<0> b; 

未调用的函数模板不会实例化,但任何函数模板都必须至少具有有效的模板参数列表。

编写此模板的一种方法是

template<int R = RowCnt, int C = ColCnt> 
  std::enable_if_t<R == C>
    GetInverseMatrix() {}