与MSVC++ 2008相比,我最近发现了一个有趣的g ++行为.考虑这个小程序:
#include <cstdlib>
const int ARR_LENGTH = 512;
void doSomething( int iLen );
int main( int argc, char** argv )
{
doSomething( ARR_LENGTH );
return 0;
}
void doSomething( int iLen )
{
int iTest[iLen];
return;
}
Run Code Online (Sandbox Code Playgroud)
它会编译吗?你怎么看?根据我对C(或C++)的了解,这不应该编译,因为我可以用我想要的任何整数调用函数doSomething(),因此在编译时无法确定iTest数组的大小.但是,当我尝试用g ++编译它时,它工作得很好.现在我可以理解这里可能发生了什么 - 编译器注意到我只将一个编译时常量作为参数调用此函数.这里有一些严肃的优化......但是当我尝试使用MSVC++ 2008编译它时,我得到了这个:
1>c:\prj\test\test.cpp(15) : error C2057: expected constant expression
1>c:\prj\test\test.cpp(15) : error C2466: cannot allocate an array of constant size 0
1>c:\prj\test\test.cpp(15) : error C2133: 'iTest' : unknown size
Run Code Online (Sandbox Code Playgroud)
我的问题是:这如何符合语言的定义(C标准(C++标准))?g ++是否可以进行这样的优化(在这种情况下很容易看到,但是第一次遇到它时,它出现在一个大型项目中,乍一看并没有多大意义).
c++ compiler-construction optimization compile-time-constant
考虑这段代码;
#define A 5
#define B 3
int difference = A - B;
Run Code Online (Sandbox Code Playgroud)
"差异"的值在编译时硬编码为"2",还是在运行时计算?
有没有办法将枚举转换为常量表达式?我希望我的switch操作符在枚举的值中进行选择,但是我得到了一个编译错误"case表达式必须是常量表达式",所以我试着在变量中声明它:
final int REG = MyEnum.REG.getIndex().intValue();
switch (service.getIndex()) {
case REG:
Run Code Online (Sandbox Code Playgroud)
但我仍然得到同样的错误.根据Oracle的文档http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28
编译时常量表达式是表示基本类型的值的表达式或不突然完成的字符串,仅使用以下内容组成:
•原始类型的文字和String类型的文字
所以它没有用,因为我没有使用文字.我想我必须声明为:
final int REG = 8;
Run Code Online (Sandbox Code Playgroud)
但是把它与枚举联系起来要好得多.有没有办法做到这一点?
编辑
结果我不需要使用任何最终变量.这很简单:
switch (service) {
case REG:
Run Code Online (Sandbox Code Playgroud)
在我看到安德里亚的评论之前,我没有想到这一点.谢谢你的回答.
在我们的项目中,我们使用printf兼容函数将消息添加到外部日志文件中.我们可以写
__LOG_INFO( "number of files = %d\n", number_of_files );
__LOG_INFO( "Just for information\n" );
Run Code Online (Sandbox Code Playgroud)
函数声明__LOG_INFO看起来像这样
template<int N>
inline void __LOG_INFO( const char (&fmt)[N] )
{
call_printf( MODULE_NAME, fmt, debug_parameters() );
}
template<int N, typename T1>
static void __LOG_INFO( const char (&fmt)[N], const T1 &t1 )
{
call_printf( MODULE_NAME, fmt, debug_parameters( t1 ) );
}
template<int N, typename T1, typename T2>
static void __LOG_INFO( const char (&fmt)[N], const T1 &t1, const T2 &t2 )
{
call_printf( MODULE_NAME, fmt, debug_parameters( …Run Code Online (Sandbox Code Playgroud) templates compile-time-constant compile-time constexpr c++11
在C++中,指针值可能是编译时常量.这是正确的,否则,非类型模板参数constexpr将无法使用指针.但是,据我所知,静态存储的函数和对象的地址(至少)在链接时而不是编译时是已知的.以下是一个例子:
main.cpp中
#include <iostream>
template <int* p>
void f() { std::cout << p << '\n'; }
extern int a;
int main() {
f<&a>();
}
Run Code Online (Sandbox Code Playgroud)
a.cpp
int a = 0;
Run Code Online (Sandbox Code Playgroud)
我只是想a知道在编译时如何知道地址main.cpp.我希望有人可以向我解释一下.
特别要考虑这一点
template <int* p, int* pp>
constexpr std::size_t f() {
return (p + 1) == (pp + 7) ? 5 : 10;
}
int main() {
int arr[f<&a, &b>()] = {};
}
Run Code Online (Sandbox Code Playgroud)
应该如何arr分配存储空间?
PLUS:这种机制似乎相当强大.即使我启用了随机基址,也可以获得正确的输出.
编译时表达式很好,因为您可以使用它们来专门化模板.因此,例如,可以通过使用该std::get方法的编译时表达式来访问元组.
std::cout << std::get<0>(my_tuple) << std::endl;
Run Code Online (Sandbox Code Playgroud)
现在,上面的表达非常难看.我正在尝试自己开发某种元组(希望将它转换为编译时字典),这样,他们就会在表单中公开一个方法:
my_dict.get<0>();
Run Code Online (Sandbox Code Playgroud)
现在,我想做的是用[]运算符替换它.我想知道这是否甚至可能.首先,我不知道如何只选择常量,编译时已知表达式作为我的运算符的参数.而且,返回类型将取决于常量表达式的值.
然而,通过定义,我可以通过类似的东西更接近我想要的东西
#define item(x) get<x>()
Run Code Online (Sandbox Code Playgroud)
这样我就可以使用了
my_dict.item(0)
Run Code Online (Sandbox Code Playgroud)
有没有办法得到比这更好的东西?
我想计算一个的阶乘const。我想结束这样的事情:
const N: usize = 4;
const N_PERMUTATIONS = factorial(N);
Run Code Online (Sandbox Code Playgroud)
显而易见的解决方案(不起作用)是:
const fn–不允许(或至少不实施)条件语句const fn,以下任何一种都不会编译:
const fn factorial(n: usize) -> usize {
match n {
0 => 1,
_ => n * factorial(n-1)
}
}
Run Code Online (Sandbox Code Playgroud)
const fn factorial(n: usize) -> usize {
if n == 0 {
1
} else {
n * factorial(n-1)
}
}
Run Code Online (Sandbox Code Playgroud)宏–在所有宏扩展之后执行表达式的评估。此宏将永远不会达到基本情况,因为经过四次迭代后,参数为4-1-1-1-1,与以下参数不匹配0:
macro_rules!factorial {
(0) => (1);
($n:expr) => ($n * factorial($n-1));
}
Run Code Online (Sandbox Code Playgroud)我还尝试了以下方法,如果*进行了短路评估,该方法将起作用,但是按原样进行无条件递归会导致堆栈溢出:
const …Run Code Online (Sandbox Code Playgroud) 我以为我会尝试通过散列来选择不同的选项作为字符串,但这不起作用:
#include <type_traits>
#include <string>
inline void selectMenuOptionString(const std::string& str)
{
switch (std::hash<std::string>()(str))
{
case std::hash<std::string>()(std::string("Selection one")) : break;
// Expression must have a constant value
}
}
inline void selectMenuOptionString2(const std::string& str)
{
size_t selectionOneHash = std::hash<std::string>()(std::string("Selection one"));
switch (std::hash<std::string>()(str))
{
case selectionOneHash: // Expression must have a constant value
// The variable of selectionOneHash cannot be used as a constant
}
constexpr size_t hash = std::hash<int>()(6); // Expression must have a constant value
}
Run Code Online (Sandbox Code Playgroud)
似乎我无法在编译时获取哈希值.根据我的阅读,每次不同的输入应该每次产生相同的唯一输出,碰撞的可能性非常低.鉴于这些属性无法在编译时计算哈希值?我对哈希很不了解,我通常使用unordered_map,但我想尝试新的东西以便学习.
#include <type_traits>
int main()
{
std::is_constructible_v<int&, const int&>; // false, as expected.
std::is_copy_constructible_v<int&>; // true, NOT as expected!
}
Run Code Online (Sandbox Code Playgroud)
根据cppref:
如果T是对象或引用类型,则变量定义为T obj(std :: declval()...); 形式良好,提供成员常数值等于true.在所有其他情况下,价值是错误的.
std::is_copy_constructible_v<int&>应该给出相同的结果std::is_constructible_v<int&, const int&>; 但是,clang 7.0如上所示给出不同的结果.
这种行为是否符合C++标准?
如果我有一个功能
int calcStuff_dynamic(const int a, const int b)
Run Code Online (Sandbox Code Playgroud)
和一些模板元代码
template<int a, int b>
struct calcStuff_static {
static const int value = //some more code
};
Run Code Online (Sandbox Code Playgroud)
有没有办法写一个包装器
int calcStuff(const int a, const int b) {
IF_THESE_ARE_KNOWN_CONSTANTS_AT_COMPILE_TIME(a, b)
return calcStuff_static<a, b>::value;
ELSE_TEMPLATE_WOULD_FAIL
return calcStuff_dynamic(a, b);
}
Run Code Online (Sandbox Code Playgroud) c++ templates compile-time-constant compile-time template-meta-programming