I have a function "has_holes", which shall calculate something based on a mask. The number of bits is determined by the type of "mask". Therefore I want to use a template. Furthermore, I only want to allow instantiations of has_holes which take parameters by value. So I added a typetrait "remove_all_t" which gives the underlying type. But when I do so, I cant build it any more getting the error:
"error: no matching function for call to 'has_holes(unsigned int&)" note: candidate template ignored: couldn't infer template argument 'BASE_TYPE'
However, if I explicitly call the funktion instantiation "has_holes it works. Did I mess up template instantiation and type deduction rules? Or where is my mistake?
Here is the code:
#include <iostream>
#include <limits>
#include <type_traits>
#include <experimental/type_traits>
//removes everything except arrays []
template<class T> struct remove_all { typedef T type; };
template<class T> struct remove_all<T*> : remove_all<T> {};
template<class T> struct remove_all<T&> : remove_all<T> {};
template<class T> struct remove_all<T&&> : remove_all<T> {};
template<class T> struct remove_all<T const> : remove_all<T> {};
template<class T> struct remove_all<T volatile> : remove_all<T> {};
template<class T> struct remove_all<T const volatile> : remove_all<T> {};
template<class T>
using remove_all_t = typename remove_all<T>::type;
template<typename BASE_TYPE, class = typename std::enable_if_t<std::experimental::is_unsigned_v<BASE_TYPE>, BASE_TYPE>>
bool has_holes(remove_all_t<BASE_TYPE> mask){ //remove "remove_all_t<>" and it will work
static_assert(std::numeric_limits<unsigned int>::max() > std::numeric_limits<decltype(mask) >::digits, "Base_type has to much digits max_digits=std::numeric_limits<unsigned int>::max()");
for (unsigned int pos{1}; pos<std::numeric_limits<decltype(mask)>::digits; ++pos ){
;//algorithm will be placed here, not implemented yet
}
return true;
}
int main()
{
unsigned int mask = 0b00110011;
auto result = has_holes<unsigned int>(mask); //works
auto result2 = has_holes(mask);//error: no matching function for call to 'has_holes(unsigned int&)'|
std::cout<<result<<" ..."<<result2<<std::endl;
return 0;
}
Best regards, Hendrik
In C++ template deduction is not unlimited. It will refuse to attempt to invert possibly Turing-complete processes.
The C++ standard calls this a non-deduced context: a context in which template arguments will not be deduced.
remove_all_t<BASE_TYPE>
induces a non-deduced context. Because when you map a type through a template like remove_all_t<X>
in theory the mapping process could be Turing complete.
And in general, template type maps do not tell C++ how to invert them. The standard tells compilers not to try.
Remove remove_all_t<BASE_TYPE>
and replace with BASE_TYPE
and it will be deduced as a value, always.
If you are afraid someone will pass int&
explicitly as a template type parameter, add a static_assert( std::is_same<remove_all_t<BASE_TYPE>, BASE_TYPE>::value, "values only");
to the body of the function.