To support portability I want to choose a constant based on the fact whether size_t
is 32 bit or 64 bit.
The code:
using namespace std;
namespace detail {
template<enable_if<is_same<size_t, uint32_t>::value,void*>::type = nullptr>
constexpr static const size_t defaultSizeHelper() {
return ( (size_t) 1 << 30 ) / 2 * 5; //2,5 Gb
}
template<enable_if<is_same<size_t, uint64_t>::value,void*>::type = nullptr>
constexpr size_t defaultSizeHelper() {
return numeric_limits<size_t>::max() / 2;
}
}
constexpr static size_t defaultSize = detail::defaultSizeHelper();
This code doesn't compile because of the error: 'std::enable_if<false, void*>::type' has not been declared. template<enable_if<is_same<size_t, uint64_t>::value,void*>::type = nullptr>
Compiler - GCC 4.9
It seems to me that the compiler doesn't apply a SFINAE principle to a constexpr
. What should I do then?
SFINAE stands for Substitution Failure Is Not An Error.
Neither of your two templates fail during instantiation, instead one of them will fail the second the compiler takes a look at it (because it will see that the enable_ifs does not depend on a template parameter, and try to expand them directly).
The solution is to make the check depend on some template-parameter, so that the compiler can only check the condition upon a potential instantiation.
In your case the easiest solution will be to simply provide a default template-argument that is the type that you would like to check against (T
in the below).
using namespace std;
namespace detail {
template<class T = uint32_t, typename enable_if<is_same<size_t, T>::value,void*>::type = nullptr>
constexpr static const size_t defaultSizeHelper() {
return ( (size_t) 1 << 30 ) / 2 * 5; //2,5 Gb
}
template<class T = uint64_t, typename enable_if<is_same<size_t, T>::value,void*>::type = nullptr>
constexpr size_t defaultSizeHelper() {
return numeric_limits<size_t>::max() / 2;
}
}
constexpr static size_t defaultSize = detail::defaultSizeHelper();
Note: An alternative solution would be to combine the two functions into one, and use the ternary-operator to either return the result of one expression, or another..
Note: Now that the check is dependent on a template-parameter, make sure you understand why you need to use
typename
to disambiguate the enable if. See this answer for more information.