【问题标题】:How does the compiler optimize templates?编译器如何优化模板?
【发布时间】:2015-10-31 05:21:55
【问题描述】:

这样写代码有意义吗?

template<bool X>
double foo(double x){
     return (X) ? moo(x) : bar(x);
}

我知道有更好的方法来实现这个例子,但我想知道,假设编译器将识别死代码并将其实例化为一般来说是否安全

double foo<true>(double x){return moo(x);}
double foo<false>(double x){return bar(x);}

【问题讨论】:

  • 回答“如何”可能有点乏味,但编译器肯定会按照您的期望进行。这绝对是基本的优化。
  • @Columbo 所以这个问题要么太琐碎要么太宽泛;)但是,我对答案很满意
  • 这里的优化和模板关系不大——编译器如果能看到b的值,也会优化inline double foo(bool b, double x) { return b ? moo(x) : bar(x); }
  • @TravisGockel 是的,但我更喜欢让它在代码中可见,只有一半会被编译
  • @tobi303 我知道您来自哪里,但实际上并非如此。条件运算符的两边都被编译了——它们只是碰巧在大多数时候都得到了优化。如果您要无法编译(如:编译器只能看到moo(x)bar(x),具体取决于X),您可以使用其他技术。如果这是您想要的,我可以提供一个更详细的示例。

标签: c++ templates


【解决方案1】:

这里要记住的是,模板不同于 C# 等语言中的泛型等语言特性。

将模板视为可识别类型的高级预处理器是一种相当安全的简化。这就是Template metaprogramming (TMP) 背后的理念,基本上是编译时编程。

就像扩展预处理器模板一样,结果经过与您的正常逻辑相同的所有优化阶段。

这是一个以更符合TMP 的风格重写逻辑的示例。这使用了函数特化。

template<bool X>
double foo(double x);

template<>
double foo<true>(double x)
{
    return moo(x);
}

template<>
double foo<false>(double x)
{
    return bar(x);
}

TMP 实际上是偶然发现的,几乎是STLBoost 的生计。

它是turing complete,因此您可以在编译时进行各种计算。

它是惰性求值的,因此您可以通过将无效逻辑放入您不想使用的模板的特化中来实现自己的编译时断言。例如,如果我要注释掉 foo&lt;false&gt; 特化并尝试像 foo&lt;false&gt;(1.0); 一样使用它,编译器会抱怨,尽管它会对 foo&lt;true&gt;(1.0); 非常满意。

Here 是另一个 Stack Overflow 帖子,展示了这一点。

如果有兴趣可以继续阅读:

  1. Modern C++ Design
  2. C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond
  3. Effective C++

【讨论】:

    【解决方案2】:

    我指定了“noinline”以使其更明显,并且我通过 cin 获取值而不是使用常量值来确保编译器不会完全删除该函数。

    如你所见,都有各自的功能。

    true => +0x1780
    false => +0x1790
    

    模板函数总是有自己的基于模板参数的函数

    【讨论】:

    • 你在 括号是我想说的。
    • 在传递给模板的上下文中,它被称为 模板参数
    • 问题不是会不会有两个不同的功能,而是两个会不会有死码
    • 啊,我完全错过了,我在以低层次的心态思考。编译器显然避免了 if (true == true) true_case();
    【解决方案3】:

    ...一般来说,假设编译器会识别出死亡是安全的 代码并将其实例化为

    double foo<true>(double x){return moo(x);}
    double foo<false>(double x){return bar(x);}
    

    从迂腐的角度来看,答案是。真正发生的是你最终会得到两个看起来像这样的函数:

    template <>
    double foo<true>(double x) {
         return (true) ? moo(x) : bar(x);
    }
    
    template <>
    double foo<false>(double x) {
         return (false) ? moo(x) : bar(x);
    }
    

    这些功能中的每一个都将通过相当明显的死代码消除优化进行优化。您最终会得到相同的结果,但有一个中间步骤。


    有一种不同的技术可以做你想做的事,它有一些优点。您可以依靠 C++ 重载和名为 std::integral_constant 的帮助器类型,使其 100% 无法在条件表达式中编译。

    double foo(double x, std::true_type) {
        return moo(x);
    }
    
    double foo(double x, std::false_type) {
        return bar(x);
    }
    

    【讨论】:

    • 您还可以查看我对没有重载版本的答案。 C++ 不允许您部分特殊 函数模板,但您可以完全专门化一个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-05
    • 1970-01-01
    • 2016-02-14
    • 1970-01-01
    • 2011-11-07
    • 1970-01-01
    相关资源
    最近更新 更多