如何使用 enable_if 进行模板 class 成员的外联定义
How to use enable_if for out-of-line definition for a template class member
我正在尝试了解 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 函数未被编译器专门化?
EDIT1
最终目标是为 T=T1 的 U=bool 启用 Compute
并为 T=T2 的 U=bool 禁用 Compute
。这是我试图实现相同目标的另一个示例代码
#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;
}
您也应该像定义一样在声明中使用 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 如我所料拒绝了您当前的代码,因为声明和定义不匹配。
error: out-of-line definition of 'Compute' does not match any declaration in '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
另一种方法是class template specialization,将OpType::INT
和OpType::BITWISE
的实现分开。
如果打算仅为 bool
类型禁用它,请为主要 class 模板 Base<T>
实施该方法。您也需要在 Compute() 的声明中使用 enable_if
。
#include <iostream>
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);
};
template<typename T>
template<typename U>
typename std::enable_if<!std::is_same<U, bool>::value, U>::type
Base<T>::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; --> compile error
return 0;
}
EDIT1
对 Base
class 进行 class 模板专业化以获得结果。为 OpType::BITWISE
创建一个完整的专业化并实现你的 Compute
功能。
#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);
};
template<OpType T>
template<typename U>
typename std::enable_if<!std::is_same<U, bool>::value, U>::type
Base<T>::Compute(U a, U b){
return a + b;
}
template <>
struct Base<OpType::BITWISE> {
template <typename U>
U Compute(U a, U b) { return a & b;}
};
using AddOperation = Base<OpType::INT>;
using AndOperation = Base<OpType::BITWISE>;
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;
}
这并不是你问题的真正答案,但为了便于阅读,有一种更好的方法可以禁止 bool
函数的 Compute( T , T )
参数。
template <typename T>
class Base{
public:
template <typename U>
U Compute(U a, U b);
bool Compute(bool , bool) = delete;
};
我正在尝试了解 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 函数未被编译器专门化?
EDIT1
最终目标是为 T=T1 的 U=bool 启用 Compute
并为 T=T2 的 U=bool 禁用 Compute
。这是我试图实现相同目标的另一个示例代码
#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;
}
您也应该像定义一样在声明中使用 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 如我所料拒绝了您当前的代码,因为声明和定义不匹配。
error: out-of-line definition of 'Compute' does not match any declaration in '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
另一种方法是class template specialization,将OpType::INT
和OpType::BITWISE
的实现分开。
如果打算仅为 bool
类型禁用它,请为主要 class 模板 Base<T>
实施该方法。您也需要在 Compute() 的声明中使用 enable_if
。
#include <iostream>
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);
};
template<typename T>
template<typename U>
typename std::enable_if<!std::is_same<U, bool>::value, U>::type
Base<T>::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; --> compile error
return 0;
}
EDIT1
对 Base
class 进行 class 模板专业化以获得结果。为 OpType::BITWISE
创建一个完整的专业化并实现你的 Compute
功能。
#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);
};
template<OpType T>
template<typename U>
typename std::enable_if<!std::is_same<U, bool>::value, U>::type
Base<T>::Compute(U a, U b){
return a + b;
}
template <>
struct Base<OpType::BITWISE> {
template <typename U>
U Compute(U a, U b) { return a & b;}
};
using AddOperation = Base<OpType::INT>;
using AndOperation = Base<OpType::BITWISE>;
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;
}
这并不是你问题的真正答案,但为了便于阅读,有一种更好的方法可以禁止 bool
函数的 Compute( T , T )
参数。
template <typename T>
class Base{
public:
template <typename U>
U Compute(U a, U b);
bool Compute(bool , bool) = delete;
};