【问题标题】:Is it possible to check if const value is known at compile time?是否可以在编译时检查 const 值是否已知?
【发布时间】:2016-05-25 14:37:01
【问题描述】:

目前我正在重写/扩展我的 C++ 实用程序库,并考虑到新的 C++11 功能。其中一个新增功能是一个模板类,它给出了一组数字的最大值,希望在编译时。

template<typename T, T... Xs> class ConstMax
{
private:
    template<typename... Ts> static constexpr T Max(Ts... xs);

    template<typename Tx> static constexpr T Max(Tx x)
    {
        return x;
    }

    template<typename T1, typename T2, typename... Ts> static constexpr T Max(T1 x, T2 y, Ts... xs)
    {
        return y > x ? Max<T2, Ts...>(y, xs...) : Max<T1, Ts...>(x, xs...);
    }

public:
    static const T Value = Max(Xs...);
};

这个类的一个示例使用:

int max = ConstMax<int, 1, 8, 66, 32, 90, 12, 33>::Value;

这里是另一个例子,它可能使验证 ConstMax<...>::Value 是否在编译时实际被评估变得更加困难:

template<typename... Ts> class Variant
{
public:
    static const size_t MaxValueSize = ConstMax<size_t, sizeof(Ts)...>::Value;
};

这导致max = 90。我使用 gdb 遍历了这段代码,似乎在分配 max 期间没有执行任何函数调用。

我的问题:

  1. 我可以安全地假设ConstMax&lt;...&gt;::Value 在编译时总是已知的吗?
  2. 有没有办法检查 constexpr 函数/方法是否在编译时被评估?
  3. 我了解定义为constexpr 的成员/方法/函数不一定在编译时进行评估,Value 被定义为static const 的事实是否会对此有所改变,或者我是否最好执行此特定情况作为递归模板类?

【问题讨论】:

    标签: c++ c++11 constexpr


    【解决方案1】:

    要检查表达式是否为 constexpr(即常量表达式),您可以使用 std::integral_constant 类型特征,如下所示:

    #include <iostream>
    #include <type_traits>
    
    template<typename T, T... Xs> class ConstMax {
      template<typename... Ts> static constexpr T Max(Ts... xs);
      template<typename Tx> static constexpr T Max(Tx x) { return x;}
      template<typename T1, typename T2, typename... Ts>
      static constexpr T
      Max(T1 x, T2 y, Ts... xs) {
            return y > x ? Max<T2, Ts...>(y, xs...) : Max<T1, Ts...>(x, xs...);
      }
    public:
        static const T Value = Max(Xs...);
    };
    
    int main() {
     std::cout << std::integral_constant<int, ConstMax<int, 1, 8, 66, 32, 90, 12, 33>::Value>::value << std::endl;   
    }
    

    Live Demo

    如果不是constexpr,它将中断编译过程。

    【讨论】:

    • 谢谢,这将成为我单元测试的一个非常好的扩展。
    【解决方案2】:
    1. 我可以安全地假设 ConstMax<...>::Value 在编译时总是已知的吗?

    是的,因为它是用常量表达式初始化的。但我会将Value 修改为constexpr 而不仅仅是const

    1. 有没有办法检查 constexpr 函数/方法是否在编译时进行评估?

    是的。尝试在 constexpr 表达式中使用它们。如果它有效,它们将在编译时进行评估。如果它无法编译,那么它不会在编译时被评估。

    1. 我了解定义为 constexpr 的成员/方法/函数不一定在编译时进行评估,Value 被定义为静态 const 的事实是否会对此有所改变,或者我最好将这种特定情况作为递归模板类来实现?

    如果您在常量表达式中使用成员,您将强制它们在编译时进行评估。所以如果你在乎的话,我会确保在常量表达式中评估它们(通过constexpr)。

    【讨论】:

    • 感谢您的快速回复。我确实更喜欢 constexpr 方法,而不是使用递归模板,很高兴知道这不会影响评估时间。
    • 如何通过调用函数来判断函数在编译时是否为 constexpr?如果参数之一不是 constexpr,那么调用也会失败,对吧?
    • @Alex:是的,如果你尝试在常量表达式中计算函数,而它不是常量表达式,编译会失败。
    • @Cornstalks 你能断定错误来自函数定义而不是参数定义吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-01
    • 2017-02-06
    • 2015-09-11
    • 2022-01-12
    • 1970-01-01
    • 2010-12-30
    • 2021-10-26
    相关资源
    最近更新 更多