【问题标题】:Type trait to receive T::value_type if present, T otherwise输入 trait 以接收 T::value_type 如果存在,否则为 T
【发布时间】:2020-06-04 20:23:12
【问题描述】:

必需是类型 T 的类型特征,如果 T 提供 typedef type 类型为 T::value_type 有一个 typedef value_type,否则有 T

我尝试了以下实现,但它似乎不起作用(typedef 始终是 T 类型,即使存在 T::value_type 也是如此):

template <class T, class = void> struct value_type { using type = T; };
template <class T> struct value_type<T, typename T::value_type> { using type = typename T::value_type; };

template <class T> using value_type_t = typename value_type<T>::type;

std::is_same_v<value_type_t<int>, int> // true
std::is_same_v<value_type_t<std::optional<int>>, int> // false, should be true

有什么想法吗?

【问题讨论】:

    标签: c++ templates sfinae typetraits


    【解决方案1】:

    专业化需要匹配基本模板。

    您的基本模板有class = void,这意味着您的专业化中的第二个参数需要为空才能匹配。

    这样做的方法是使用std::void_t 之类的东西,无论我们在其中放入什么,它都会变为无效。这里的唯一目的是允许 SFINAE,如果 T::value_type 有效,我们总是得到 void

    template <class T, class = void> struct value_type { using type = T; };
    template <class T> struct value_type<T, std::void_t<typename T::value_type>> { using type = typename T::value_type; };
    
    template <class T> using value_type_t = typename value_type<T>::type;
    

    【讨论】:

    • 谢谢,它有效。但是为什么它必须匹配void?我认为编译器将选择最佳匹配的专业化(在这种情况下为T::value_type),如果没有value_type typedef 则将其 SFINAE 出来,因此求助于非专业化版本。 void 作为默认参数(仅)用于通过单个参数启用 value_type_t 别名。有没有其他方法可以在不需要 void_t 的情况下实现这个特性(直到 C++17 才出现)?
    • @Lars 因为这就是部分模板专业化的工作方式。首先实例化主模板,然后任何与主模板参数匹配的特化都被认为是有效的。如果您在没有部分特化的情况下执行 SFINAE(例如使用重载模板函数的返回值),还有其他方法,但在这种情况下,没有更清洁或更简单的方法 AFAIK。
    • @Lars 看看不涉及 SFINAE 的部分专业化是如何工作的,我想你会更好地了解它为什么会这样工作。在 SFINAE 中混合只是使用它的一种方式,但它仍然需要遵循与任何“正常”部分专业化相同的规则。
    猜你喜欢
    • 2021-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-17
    • 2022-12-02
    • 1970-01-01
    • 2019-10-03
    相关资源
    最近更新 更多