函数模板和type_traits

时间:2017-04-28 11:43:13

标签: c++ templates typetraits type-deduction

我有一个函数“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;
}

祝你好运, 亨德里克

3 个答案:

答案 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>::typeA = 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;
}

Simplified example