我的部分模板专业化的模板参数是不可推导的

The template parameter of my partial template specialization is not deducible

本文关键字:专业化 我的部 参数      更新时间:2023-10-16

请考虑以下代码片段:

template<class E>
class vector_expression {};
template<class Tuple>
class vector
    : public vector_expression<vector<Tuple>>
{
public:
    using value_type = typename Tuple::value_type;
};
template<typename T>
using dynamic_vector = vector<std::vector<T>>;
namespace detail
{
    template<class E>
    constexpr bool is_vector_expression_v = std::is_base_of_v<vector_expression<std::decay_t<E>>, std::decay_t<E>>;
    template<class E>
    struct value_type { using type = std::decay_t<E>; };
    template<class E>
    struct value_type<vector_expression<std::decay_t<E>>> { using type = typename std::decay_t<E>::value_type; };
    template<class E>
    using value_type_t = typename value_type<E>::type;
}

int main()
{
    static_assert(std::is_same<detail::value_type_t<dynamic_vector<double>>, double>::value, "not the same");   
    return 0;
}

每当Evector_expression时,我希望value_type_t<E>是在E中指定的value_type。上面的代码不起作用,因为模板参数Evalue_type的部分专用化中是不可推导的。如何使代码正常工作?

演示

std::decay_t<E>是不可推导的,因为它实际上是std::decay<E>::type(事实上,在您的特定情况下,几个E可以导致相同的类型)。

第二个修复程序需要通过static_assert:

由于dynamic_vector<double>不是vector_expression,而是从中继承的,所以您的专业化不匹配。你可以使用SFINAE来解决这个问题:

template<class E, typename Enabler = void>
struct value_type { using type = std::decay_t<E>; };
template<class E>
struct value_type<E, std::enable_if_t<is_vector_expression_v<E>>> {
    using type = typename std::decay_t<typename E::type>::value_type;
};

演示

第一个问题是你的部分专业化是不可推导的。这是一个更容易的解决方案,你只需放下std::decay_t:

template<class E>
struct value_type<vector_expression<E>> { using type = typename E::value_type; };

然而,现在你有一个更大的问题,那就是它不能做你想做的事情。dynamic_vector<double>不是任何Evector_expression<E>。它从vector_expression<vector<std::vector<T>>>继承了,但这对本次匹配没有帮助。因此,上面的修复程序将进行编译,但您仍然会匹配主模板,从而得到错误的value_type

您可能想要的是专门研究value_type作为typedef的存在。即:

template <class... > using void_t = void;
template <class T> struct tag_t { using type = T; }; // courtesy of Yakk
template<class E, class=void>
struct value_type : tag_t<std::decay_t<E>> { };
template<class E>
struct value_type<E, void_t<typename std::decay_t<E>::value_type>> 
: tag_t<typename std::decay_t<E>::value_type> { };

现在你的static_assert通过了。