传递 constexpr 对象

Passing constexpr objects around

本文关键字:对象 constexpr 传递      更新时间:2023-10-16

我决定给constexpr一个新的C++14定义,为了充分利用它,我决定写一个小的编译时字符串解析器。但是,我正在努力使我的对象保持constexpr,同时将其传递给函数。请考虑以下代码:

#include <cstddef>
#include <stdexcept>
class str_const {
    const char * const p_;
    const std::size_t sz_;
public:
    template <std::size_t N>
    constexpr str_const( const char( & a )[ N ] )
    : p_( a ), sz_( N - 1 ) {}
    constexpr char operator[]( std::size_t n ) const {
        return n < sz_ ? p_[ n ] : throw std::out_of_range( "" );
    }
    constexpr std::size_t size() const { return sz_; }
};
constexpr long int numOpen( const str_const & str ){
    long int numOpen{ 0 };
    std::size_t idx{ 0 };
    while ( idx <  str.size() ){
        if ( str[ idx ] == '{' ){ ++numOpen; }
        else if ( str[ idx ] == '}' ){ --numOpen; }
        ++idx;
    }
    return numOpen;
}
constexpr bool check( const str_const & str ){
    constexpr auto nOpen = numOpen( str );
    // ...
    // Apply More Test functions here,
    // each returning a variable encoding the correctness of the input
    // ...
    return ( nOpen == 0 /* && ... Test the variables ... */ );
}
int main() {
    constexpr str_const s1{ "{ Foo : Bar } { Quooz : Baz }" };
    constexpr auto pass = check( s1 );
}

我使用Scott Schurr在C++Now 2012上提出的str_const类,该类为C++14进行了修改。

上面的代码将无法编译并显示错误(clang-3.5(

error: constexpr variable 'nOpen' must be initialized by a constant expression  
    constexpr auto nOpen = numOpen( str );  
                           ~~~~~~~~~^~~~~

这使我得出的结论是,你不能在不失去其constexpr性的情况下传递constexpr对象。这让我想到以下问题:

  1. 我的解释正确吗?

  2. 为什么这是标准规定的行为?

    我认为传递constexpr对象没有问题。当然,我可以重写我的代码以适应单个函数,但这会导致代码狭窄。我认为将单独的功能分解为单独的代码单元(函数(也应该是编译时操作的良好风格。

  3. 正如我之前所说,编译器错误可以通过将代码从单独的测试函数(例如numOpen(的主体移动到顶级函数check的主体来解决。但是,我不喜欢这个解决方案,因为它创建了一个巨大而狭窄的功能。你看到解决问题的不同方法吗?

原因是在

constexpr 函数参数不是常量表达式,无论参数是否是常量表达式。您可以在其他函数中调用constexpr函数,但constexpr函数的参数不会在内部constexpr,这使得任何函数调用(甚至对constexpr函数(都不是内部的常量表达式。

const auto nOpen = numOpen( str );

就足够了。只有当您从外部查看调用时,才会验证内部表达式的constexpr性,从而决定是否constexpr整个调用。