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;
}