C++ constexpr函数可能存在错误?
以下代码是否正确使用了C++ constexpr函数可能存在错误?,c++,visual-c++,constexpr,C++,Visual C++,Constexpr,以下代码是否正确使用了constexpr函数?它基本上尝试以各种方式访问静态constepr成员变量\u size 它使用g++编译时没有问题,但在msvc-2017/2019和clang时失败 代码样本可通过导栓进行测试 如果将constexpr函数替换为等效的宏解决方案,似乎可以编译(任何地方)。取消注释使用\u宏\u变通方法进行测试 对我来说,这似乎暗示了一个与constexpr函数相关的编译器错误 (由于宏版本可以工作,这表明编译器应该有足够的编译时信息来处理constepr函数。显然
constexpr
函数?它基本上尝试以各种方式访问静态constepr
成员变量\u size
它使用g++
编译时没有问题,但在msvc-2017/2019
和clang
时失败
代码样本可通过导栓进行测试
如果将
constexpr
函数替换为等效的宏解决方案,似乎可以编译(任何地方)。取消注释使用\u宏\u变通方法进行测试
对我来说,这似乎暗示了一个与constexpr
函数相关的编译器错误
(由于宏版本可以工作,这表明编译器应该有足够的编译时信息来处理constepr
函数。显然g++
可以做到这一点……)
(这个例子只是一个简单的发明,真正的代码是它的一部分)
#包括
//定义使用\u宏\u解决方法
模板
结构扩展
{
size\u t static constexpr\u size=N;
双xdat[N];
};
#如果已定义(使用\u宏\u变通方法)
//丑陋的基于宏的黑客,相当于编译
//time foo()。。。
//到处都有编译吗
#定义foo(_aa,_bb)_aa._size+_bb._size
#否则
//为什么会产生问题?适用于g++7,
//8、9,但不包括msvc等
模板
内联大小\u t constexpr foo(
扩展常数&_aa,
扩展常数&bb
)
{
返回_aa._size+_bb._size;
}
#endif//使用\u宏\u解决方法
模板
内联空隙粘液(
扩展常数&_xx,
扩展常数
)
{//这将不会使用msvc编译,报告
//C2131:表达式的计算结果不是常数
扩展;
}
int main()
{
扩展<2>\ux2;
扩展<4>\u x4;
//这似乎对g++和msvc都有效
扩展x6;
//通过msvc,这会导致上述错误
goo(x2,x4);
返回0;
}
根据cppreference.com:
引用变量可以声明为constexpr(其初始值设定项必须是引用常量表达式):
此程序的问题是,您试图在constexpr上下文中使用对运行时变量(在main开头声明)的引用。尽管在对象内部访问的变量是全局状态(静态)且在constexpr上下文内部,但在这种情况下不能使用这些运行时变量的地址。除了GCC 9.0和更早版本之外,我无法获得您提供的代码,您可以使用任何现代编译器进行编译。GCC主干无法编译
我能够使用系统级程序员这一最好的工具来测试这一点。
有趣的是,如果我们决定在调用goo()
时按值复制这些变量,那么这些变量似乎可以使用。通过从函数签名中删除符号,我能够在每个clang、gcc和msvc的多个版本上编译此程序:
#包括
#包括
模板<
大小N=+1
>
阶级扩张
{
公众:
size\u t static constexpr\u size=N;
双xdat[N];
尺寸=0;
};
模板<
尺码不适用,尺码不适用
>
内联大小\u t constexpr foo(
扩展常数&_aa,
扩展常数&bb
)
{
返回_aa._size+_bb._size;
}
模板<
尺码不适用,尺码不适用
>
内联空隙粘液(
扩展常数xx,
扩展常数
)
{
//这将不会使用msvc、报表进行编译
//C2131:表达式的计算结果不是常数
尺寸
constexpr _nn=foo(_xx,_yy);
扩展;
}
int main()
{
扩展<2>\ux2;
扩展<4>\u x4;
//这似乎对g++和msvc都有效
尺寸
constexpr _n6=foo(_x2,_x4);
扩展x6;
//通过msvc,这会导致上述错误
goo(x2,x4);
std::非常感谢您看到了这一点,但我不确定这是否解决了问题---编译时访问的\u size
成员变量到处都是静态constexpr
,因此我不清楚为什么这不应该起作用。这也将使用g++7.4
和通过ideone(g++8.3
)为我编译。
#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;
}