函数模板和 type_traits 的问题

Problems with function template and type_traits

我有一个函数"has_holes",它会根据掩码计算一些东西。位数由"mask"的类型决定。因此我想使用模板。此外,我只想允许 has_holes 的实例化,它按值获取参数。所以我添加了一个 typetrait "remove_all_t" 来给出底层类型。但是当我这样做时,我无法再构建它并收到错误消息:

"error: no matching function for call to '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;
}

此致, 亨德里克

在 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");

既然你关心的是位数,那么在算出位数的时候做类型缩减就好了。

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*(所以必须修改它)。

模板参数推导已尝试,如[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