我的部分模板特化的模板参数不可推导
The template parameter of my partial template specialization is not deducible
请考虑以下代码片段:
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;
}
只要 E
是 vector_expression
,我希望 value_type_t<E>
成为 E
中指定的 value_type
。上面的代码不起作用,因为模板参数 E
在 value_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>
不是任何 E
的 vector_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
通过了。
请考虑以下代码片段:
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;
}
只要 E
是 vector_expression
,我希望 value_type_t<E>
成为 E
中指定的 value_type
。上面的代码不起作用,因为模板参数 E
在 value_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>
不是任何 E
的 vector_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
通过了。