首页 > 解决方案 > 如何使用 enable_if 进行模板类成员的离线定义

问题描述

我正在尝试了解的用法,enable_if但我确实遇到了一些困难。在这里,我编写了一个似乎无法按预期工作的测试代码。

#include <iostream>

template <typename T>
class Base{
 public:
  template <typename U>
  U Compute(U a, U b);
};

using AddOperation = Base<int>;

template<>
template<typename U>
typename std::enable_if<!std::is_same<U, bool>::value, U>::type
AddOperation::Compute(U a, U b){
  return a + b;
}

int main(){
  Base<int> b;
  std::cout << b.Compute<int>(10, 2) << std::endl;
  std::cout << b.Compute<bool>(true, false) << std::endl;
  return 0;
}

意图:不想为bool类型启用计算

但在上面的代码中,它正在工作。如何确保 bool 的 Compute 函数没有被编译器专门化?

编辑1

最终目标是为 T=T1 启用ComputeU=bool 并为 T=T2 禁用ComputeU=bool。这是另一个示例代码,我试图通过它来实现相同的目标

#include <iostream>

enum class OpType{
  INT,
  BITWISE,
};

template <OpType T>
class Base{
 public:
  template <typename U>
  typename std::enable_if<!std::is_same<U, bool>::value, U>::type 
  Compute(U a, U b); 
};

using AddOperation = Base<OpType::INT>;

template<>
template<typename U>
typename std::enable_if<!std::is_same<U, bool>::value, U>::type
AddOperation::Compute(U a, U b){ 
  std::cout << a << "," << b << std::endl;
  return a + b;
}

using AndOperation = Base<OpType::BITWISE>;

template<>
template<typename U>
typename std::enable_if<std::is_same<U, bool>::value, U>::type
AndOperation::Compute(U a, U b){
  return a & b;
}

int main(){
  AddOperation b;
  AndOperation a;
  std::cout << b.Compute<int>(10, 2) << std::endl;
  std::cout << a.Compute<bool>(true, true) << std::endl;
  return 0;
}

标签: c++classtemplatestemplate-specialization

解决方案


您也应该enable_if在声明中使用,就像定义一样。

template <typename T>
class Base{
 public:
  template <typename U>
  typename std::enable_if<!std::is_same<U, bool>::value, U>::type Compute(U a, U b);
};

居住

事实上,clang拒绝了您当前的代码,因为声明和定义不匹配。

错误:“Compute”的外线定义与“Base”中的任何声明都不匹配


编辑(对于您添加的问题)

你可以

template <OpType T>
class Base{
 public:
  template <typename U, OpType X = T>
  typename std::enable_if<
             (X == OpType::INT && !std::is_same<U, bool>::value) 
             || 
             (X == OpType::BITWISE && std::is_same<U, bool>::value), U
           >::type
  Compute(U a, U b); 
};

using AddOperation = Base<OpType::INT>;

template<>
template<typename U, OpType X>
typename std::enable_if<
           (X == OpType::INT && !std::is_same<U, bool>::value) 
           || 
           (X == OpType::BITWISE && std::is_same<U, bool>::value), U
         >::type
AddOperation::Compute(U a, U b){ 
  std::cout << a << "," << b << std::endl;
  return a + b;
}

using AndOperation = Base<OpType::BITWISE>;

template<>
template<typename U, OpType X>
typename std::enable_if<
           (X == OpType::INT && !std::is_same<U, bool>::value) 
           || 
           (X == OpType::BITWISE && std::is_same<U, bool>::value), U
         >::type
AndOperation::Compute(U a, U b){
  return a & b;
}

然后

std::cout << b.Compute<int>(10, 2) << std::endl;       // fine
std::cout << a.Compute<bool>(true, true) << std::endl; // fine
std::cout << b.Compute<bool>(true, true) << std::endl; // error, no matching function
std::cout << a.Compute<int>(10, 2) << std::endl;       // error, no matching function

居住

另一种方法是类模板专门化OpType::INT,将和的实现分开OpType::BITWISE


推荐阅读