constexpr 条件不是常量?
constexpr condition not constant?
我写了下面的 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
if constexpr
行得到 error: ‘pCondition’ is not a constant expression
。
为什么?这行不通吗?
Why? Shouldn't this work?
不,不应该。 pCondition
不是 constant expression。我明白为什么这可能会令人困惑,因为 pCondition
是 const
- 但术语常量表达式指的是它能够在编译时求值。也就是说,不是 const
,而是 constexpr
。
函数参数不是常量表达式。您碰巧传递了编译时常量这一事实并不重要,因为您可以轻松传递从标准输入或其他内容读取的运行时变量。
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
Barry 是正确的,但我认为这并不是您理解错误的地方。
template <typename T> constexpr const T& Select(const bool pCondition, const T& a, const T& b)
意味着如果参数是,函数调用在编译时是可评估的。但是可以使用编译时未知的参数调用该函数。在这种情况下,函数调用本身不是常量表达式,将在 运行 时进行计算。尽管在函数式编程的意义上它仍然是纯粹的,顺便说一句,它是 noexcept
。
但 if constexpr (pCondition) {...
确实意味着表达式必须在编译时可计算。
因此,由于可以在编译时使用未知参数调用 constexpr 函数,因此它不能包含声明为 constexpr
的表达式(如果它们依赖于这些参数)。
所有其他答案都是正确的,并没有说出我在绊倒这个问题时想知道的事情。对于在 constexpr (compile-time) 和变量(运行时)上下文中工作的 constexpr 函数,正如 Patrick 指出的那样,函数中不能有任何将其限制为 constexpr 上下文的内容。更重要的是,您 不需要 任何此类限制即可使函数在 constexpr 上下文中工作。编译器弄清楚了——它现在可以自由地(根据需要)在 constexpr 或运行时上下文中评估函数。所以if constexpr (pCondition)
中的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
if constexpr
行得到 error: ‘pCondition’ is not a constant expression
。
为什么?这行不通吗?
Why? Shouldn't this work?
不,不应该。 pCondition
不是 constant expression。我明白为什么这可能会令人困惑,因为 pCondition
是 const
- 但术语常量表达式指的是它能够在编译时求值。也就是说,不是 const
,而是 constexpr
。
函数参数不是常量表达式。您碰巧传递了编译时常量这一事实并不重要,因为您可以轻松传递从标准输入或其他内容读取的运行时变量。
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
Barry 是正确的,但我认为这并不是您理解错误的地方。
template <typename T> constexpr const T& Select(const bool pCondition, const T& a, const T& b)
意味着如果参数是,函数调用在编译时是可评估的。但是可以使用编译时未知的参数调用该函数。在这种情况下,函数调用本身不是常量表达式,将在 运行 时进行计算。尽管在函数式编程的意义上它仍然是纯粹的,顺便说一句,它是 noexcept
。
但 if constexpr (pCondition) {...
确实意味着表达式必须在编译时可计算。
因此,由于可以在编译时使用未知参数调用 constexpr 函数,因此它不能包含声明为 constexpr
的表达式(如果它们依赖于这些参数)。
所有其他答案都是正确的,并没有说出我在绊倒这个问题时想知道的事情。对于在 constexpr (compile-time) 和变量(运行时)上下文中工作的 constexpr 函数,正如 Patrick 指出的那样,函数中不能有任何将其限制为 constexpr 上下文的内容。更重要的是,您 不需要 任何此类限制即可使函数在 constexpr 上下文中工作。编译器弄清楚了——它现在可以自由地(根据需要)在 constexpr 或运行时上下文中评估函数。所以if constexpr (pCondition)
中的constexpr
可以简单的去掉