以下代码是否正确使用constexpr
功能?它实际上试图以各种方式访问static constexpr
成员变量_size
。
使用g++
编译时没有问题,但使用msvc-2017 / 2019
和clang
失败。
可通过godbolt here进行测试的代码示例。
如果用等效的宏替代方法代替constexpr
函数,似乎可以在任何地方进行编译。取消注释USE_MACRO_WORKAROUND
进行测试。
对我来说,这似乎暗示了与constexpr
函数有关的编译器错误?
(由于宏版本有效,这表明编译器应该具有足够的编译时信息来处理constexpr
函数。显然g++
可以做到这一点...]
(此示例仅是一个简单的设计。实际代码是this library的一部分。
#include <cstddef>
//define USE_MACRO_WORKAROUND
template <size_t N = +1>
struct expansion
{
size_t static constexpr _size = N ;
double _xdat [ N ] ;
};
#if defined(USE_MACRO_WORKAROUND)
// ugly macro-based hack that's equiv. to compile
// time foo()...
// does compile everywhere
#define foo(_aa, _bb) _aa._size + _bb._size
#else
// why does this cause problems? works for g++ 7,
// 8, 9, but not msvc, etc
template <size_t NA, size_t NB>
inline size_t constexpr foo (
expansion <NA> const& _aa,
expansion <NB> const& _bb
)
{
return _aa._size + _bb._size;
}
#endif //USE_MACRO_WORKAROUND
template <size_t NA, size_t NB>
inline void goo (
expansion <NA> const& _xx,
expansion <NB> const& _yy
)
{ // this will not compile with msvc, reporting
// C2131: expression did not evaluate to a constant
expansion<foo(_xx, _yy)> _tt;
}
int main ()
{
expansion< 2 > _x2;
expansion< 4 > _x4;
// this seems to work for both g++ and msvc
expansion<foo(_x2, _x4)> _x6;
// via msvc, this leads to the errors above
goo (_x2, _x4) ;
return 0;
}
可以将引用变量声明为constexpr(它们的初始化程序必须是引用常量表达式:]
该程序的问题是,您试图在constexpr上下文中使用对运行时变量的引用(在main的开头声明)。尽管在对象内部访问的变量是全局状态(静态),并且在constexpr上下文内部,但是在这种情况下不能使用这些运行时变量的地址。除了GCC 9.0及更早版本,我无法获得您提供的使用任何现代编译器进行编译的代码。 GCC中继编译失败。
我能够使用对我们(系统级程序员,Matt Godbolt's Compiler Explorer)可用的最佳工具之一对此进行测试。Simplified example
有趣的是,如果我们决定在调用goo()
时按值复制它们,则可以使用这些变量。通过从函数签名中删除“&”号,我能够使该程序在每个clang,gcc和msvc的多个版本上进行编译:
#include <cstddef> #include <iostream> template < size_t N = +1 > class expansion { public: size_t static constexpr _size = N ; double _xdat [ N ] ; size_t _xlen = 0 ; }; template < size_t NA, size_t NB > inline size_t constexpr foo ( expansion <NA> const& _aa, expansion <NB> const& _bb ) { return _aa._size + _bb._size; } template < size_t NA, size_t NB > inline void goo ( expansion <NA> const _xx, expansion <NB> const _yy ) { // this will not compile with msvc, reporting // C2131: expression did not evaluate to a constant size_t constexpr _nn = foo(_xx, _yy); expansion<_nn> _tt; } int main () { expansion< 2 > _x2; expansion< 4 > _x4; // this seems to work for both g++ and msvc size_t constexpr _n6 = foo(_x2, _x4); expansion<_n6> _x6; // via msvc, this leads to the errors above goo (_x2, _x4) ; std::cout << _n6 << std::endl; return 0; }
编辑:
因为我无法确认它是否是编译器错误,(因为我无法复制您说的结果),我希望我能够帮助您使用提供的代码,因为是您遇到的合法用例。