constexpr条件不是常数?

时间:2018-12-03 18:08:12

标签: c++ c++17 constexpr if-constexpr

我编写了以下C ++ 17代码:

constexpr bool gDebug = true;

template <typename T> constexpr const T& Select(const bool pCondition, const T& a, const T& b)
{
   if constexpr (pCondition)
   {
      return a;
   }
   else
   {
      return b;
   }
}

然后我这样称呼它:

int c = Select<QString>(gDebug, a, b); // In .cpp

我在error: ‘pCondition’ is not a constant expression行中得到了if constexpr

为什么?这不行吗?

2 个答案:

答案 0 :(得分:5)

  

为什么?这不行吗?

不,不应该。 pCondition不是constant expression。我知道为什么这可能会造成混淆,因为pConditionconst-但是术语常量表达式是指它能够在编译时求值。也就是说,不是const,而是真正的constexpr

函数参数不是常量表达式。碰巧传递编译时常量这一事实并不重要,因为您可以轻松传递从stdin或其他东西读取的运行时变量。

if constexpr需要一个常量表达式,因此您实际上只想在if那里。或者,您需要将条件提升为常量表达式-例如通过使其成为模板参数:

template <bool pCondition, typename T>
constexpr const T& Select(const T& a, const T& b)
{
   if constexpr (pCondition) // now okay
   {
      return a;
   }
   else
   {
      return b;
   }
}

int c = Select<qDebug>(a, b);

或者您可以要求参数是编码为类型的值:

template <typename Boolean, typename T>
constexpr const T& Select(Boolean pCondition, const T&, const T&);

constexpr std::true_type qDebug{}; // true_type, not bool = true
int c = Select(qDebug, a, b);      // okay

答案 1 :(得分:1)

巴里(Barry)是对的,但我认为这并不是您理解上的错误所在。

template <typename T> constexpr const T& Select(const bool pCondition, const T& a, const T& b)

表示如果参数正确,则函数调用在编译时可求值。但是可以使用非常量参数调用该函数。在这种情况下,函数调用本身不是常量表达式,将在运行时求值。尽管从函数式编程的角度来看,它仍然是纯净的,顺便说一下,它是noexcept

但是if constexpr (pCondition) {...实际上意味着表达式必须在编译时可求值。

因此,由于constexpr函数可以用非const参数调用,因此如果依赖于这些参数,则不能包含声明为constexpr的表达式。