我有一个函数“has_holes”,它应该根据掩码计算一些东西。位数由“掩码”的类型决定。因此我想使用模板。此外,我只想允许has_holes的实例化,它按值获取参数。所以我添加了一个typetrait“remove_all_t”,它给出了底层类型。但是,当我这样做时,我不能再建立它来得到错误:
“错误:没有匹配函数来调用'has_holes(unsigned int&)” 注意:候选模板被忽略:无法推断模板参数'BASE_TYPE'
但是,如果我明确地调用funktion实例化“has_holes它可以工作。 我搞乱了模板实例化和类型扣除规则吗?或者我的错误在哪里?
以下是代码:
#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;
}
祝你好运, 亨德里克
答案 0 :(得分:1)
在C ++模板中,演绎不是无限制的。它将拒绝尝试反转可能的图灵完成过程。
C ++标准将此称为非推导上下文:不推导出模板参数的上下文。
remove_all_t<BASE_TYPE>
会导致非推断的上下文。因为当你通过理论上的remove_all_t<X>
这样的模板映射类型时,映射过程可能是图灵完成的。
通常,模板类型映射不告诉C ++如何反转它们。该标准告诉编译器不要尝试。
删除remove_all_t<BASE_TYPE>
并替换为BASE_TYPE
,它将始终推断为值。
如果您担心有人会明确地将int&
作为模板类型参数传递,请在函数正文中添加static_assert( std::is_same<remove_all_t<BASE_TYPE>, BASE_TYPE>::value, "values only");
。
答案 1 :(得分:0)
由于您关注的是位数,所以在计算出位数时只需要减少类型。
template<typename BASE_TYPE,
class = typename std::enable_if_t<std::experimental::is_unsigned_v<remove_all_t<BASE_TYPE> > >
>
bool has_holes(BASE_TYPE mask)
{
using reduced_type = remove_all_t<BASE_TYPE>;
static_assert(std::numeric_limits<unsigned int>::max() > std::numeric_limits<reduced_type>::digits,
"Base_type has to many digits max_digits=std::numeric_limits<unsigned int>::max()");
for (unsigned int pos{1}; // really start at 1 (nor 0)?
pos < std::numeric_limits<reduced_type>::digits;
++pos )
{
//algorithm will be placed here, not implemented yet
}
return true;
}
虽然你可能不想接受BASE_TYPE*
(所以必须修改它)。
答案 2 :(得分:0)
尝试模板参数扣除 ,如[temp.deduct.call]/p1
中所述
使用P = typename remove_all<BASE_TYPE>::type
和A = unsigned int
。最终BASE_TYPE
无法推断(也不是默认),并且每[temp.deduct.type]/p2
转换为不完整的推论。
作为旁注,我会使用一个简单的解决方法(因为你已经有其他静态断言)
template<typename BASE_TYPE, class = typename std::enable_if_t<std::experimental::is_unsigned_v<BASE_TYPE>, BASE_TYPE>,
typename RBASE_TYPE = remove_all_t<BASE_TYPE>>
^^^^^^^^^^
bool has_holes(BASE_TYPE mask){
// Use RBASE_TYPE here
return true;
}