Reputation: 3343
I am trying to understand the usage of enable_if
but I do have few difficulties in the same. Here I have written a test code that doesn't seem to work as intended.
#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;
}
Intention: Don't want to enable Compute for bool
type
but in the code above, it is working. How do I make sure that the Compute function for bool is not specialized by compiler?
EDIT1
Eventual goal is to enable Compute
for U=bool for T=T1 and disable Compute
for U=bool for T=T2. Here is another example code by which I am trying to achieve the same
#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;
}
Upvotes: 3
Views: 736
Reputation: 1675
If the intention is to disable it only for bool
types, have the method implemented for the primary class template Base<T>
. You need enable_if
in the declaration of Compute() too.
#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
Do class template specialization for Base
class to achieve the results. Create a full specialization for OpType::BITWISE
and implement your Compute
function.
#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;
}
Upvotes: 0
Reputation: 172864
You should use enable_if
in the declaration too, as the definition did.
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);
};
In fact, clang rejects your current code as I expected, because the declaration and defintion don't match.
error: out-of-line definition of 'Compute' does not match any declaration in 'Base'
EDIT (for your added question)
You can
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;
}
then
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
Another approach is class template specialization, to seperate the implementation of OpType::INT
and OpType::BITWISE
.
Upvotes: 2
Reputation: 1282
It is not really answer of your question but there is a better way to forbid bool
argument for Compute( T , T )
function for sake of readability.
template <typename T>
class Base{
public:
template <typename U>
U Compute(U a, U b);
bool Compute(bool , bool) = delete;
};
Upvotes: 1