【问题标题】:How std::conditional worksstd::conditional 如何工作
【发布时间】:2017-11-16 23:19:45
【问题描述】:

我们有一个名为std::conditional 描述here 的元编程小奇迹。在同一个参考资料中,它说可能的实现是

template<bool B, class T, class F>
struct conditional { typedef T type; };

template<class T, class F>
struct conditional<false, T, F> { typedef F type; };

所以如果我在代码中做类似的事情

typename std::conditional<true,int,double>::type a;

编译器将遵循第一个定义,如果我做类似的事情

typename std::conditional<false,int,double>::type b

编译器将采用第二个。为什么这行得通?这里有什么编译规则?

【问题讨论】:

  • 现有规则是部分模板特化。

标签: c++ c++11 templates template-meta-programming template-specialization


【解决方案1】:

简而言之,它与模板专业化规则有关。这些类似于函数重载,但用于类型。

这里的编译器更喜欢更专业的类型而不是更通用的类型。

template<bool B, class T, class F>
struct conditional { typedef T type; };

template<class T, class F>
struct conditional<false, T, F> { typedef F type; };

因此,如果编译器看到模板实例化coditional&lt;false, ...&gt;,它会发现:

  • 通用模板template&lt;bool B, class T, class F&gt; struct conditional
  • 所有专业:template&lt;class T, class F&gt; struct conditional&lt;false, T, F&gt;

此时它会尝试匹配尽可能多的专业化参数,并最终选择带有false 的专业化。

例如引入另一个版本,如:

template<class F>
struct conditional<false, int, F> { typedef int type; };

并实例化像 conditional&lt;false, int, double&gt; 这样的模板类型会更喜欢专业化

template&lt;class F&gt; struct conditional&lt;false, int, F&gt;

template&lt;class T, class F&gt; struct conditional&lt;false, T, F&gt; 比具有 2 个专用参数的版本更通用。

此时的一些技巧:

甚至可以只声明最通用的情况(即模板的通用形式只是声明但未定义)并且只对您真正打算拥有的情况进行专门化。所有非特化案例都会导致编译错误,并要求用户将案例特化为特定类型。

【讨论】:

  • 哦,很好。非常感谢。这种元编程技巧非常聪明,同时看起来像黑客攻击。我想知道这个 type_traits 是否有一天会成为 C++ 中的第一批公民,并由编译器以一种更简单的模板条件语言直接实现。虽然这对编译器开发人员来说可能是一个真正的挑战。
【解决方案2】:

为什么会这样?这里有什么编译规则?

我不是专家,但我会尝试从实用的角度解释。

希望使用权利条款...

template <bool B, class T, class F>
struct conditional { typedef T type; };

(但是,对于 C++11,我更喜欢

template <bool B, typename T, typename>
struct conditional { using type = T; };

) 你声明模板

template <bool, typename, typename>
struct conditional;

并定义通用(非专用)版本。

template< class T, class F>
struct conditional<false, T, F> { typedef F type; };

(或者,在 C++11 中,

template <typename T, typename F>
struct conditional<false, T, F> { using type = F; };

) 你定义了conditional的部分特化

当一个类(或结构)的模板参数匹配两个或多个定义时,编译器选择更专业的一个;所以,对于

typename std::conditional<false,int,double>::type

类的两个定义都匹配,因此编译器选择专用的一个(带有false 的专用)并且typedouble

对于

typename std::conditional<true,int,double>::type a;

只有通用版本匹配,所以typeint

【讨论】:

  • 是的,我没有意识到第二个声明实际上被视为一种专业化。越专业,它的优先级越高。惊人的东西。谢谢
【解决方案3】:

在大多数模板元编程中,这里起作用的主要规则是 SFINAE(替换失败不是错误)。根据这个规则,如果编译器没有找到类型,那么它不会抛出错误而是向前移动并检查是否有任何未来的语句可以提供类型信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 2018-08-04
    • 1970-01-01
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    相关资源
    最近更新 更多