is_constant_evaluated() 应该产生 constexpr 变量?
is_constant_evaluated() should produce constexpr variables?
我已经阅读了 std::is_constant_evaluated()
的定义,但我仍然不确定为什么 (1) 不能使用 最新的 GCC:error: 'x' is not a constant expression
template<auto v>
struct s
{};
constexpr void f(int x)
{
if (std::is_constant_evaluated())
{
// constexpr int z=x; (1)
// s<x> a; (2)
}
}
int main(int argc, char* argv[])
{
f(4);
//f(argc);
return 0;
}
- 按照标准,这应该行得通吗?
- 或者只是 GCC 实现有问题?
- 我能以某种方式实现预期的行为吗?基本上是:
分支在 std::is_constant_evaluated()
- 如果为真:代码可以使用变量作为 constexpr(如 (2))
- 如果为假:代码使用变量作为非constexpr
更新
我可以'transport'将constexpr-essiveness信息放入函数中吗?基本上是在 f()
中决定是否用 constexpr
x 调用它。
更新
关于我想要实现的更复杂的示例:如果可能,此示例应在编译时将参数字符串化。
template<auto v>
struct dummy_stringify
{
static constexpr auto str=v==4 ? "4" : "31"; // this is just an example; imagine here a much more complex logic
};
constexpr void f(int x)
{
if (std::is_constant_evaluated())
{
std::puts("A compile time calculation:");
//std::puts(dummy_stringify<x>::str);
} else
{
std::cout<<"A runtime calculation:"<<std::endl;
std::cout<<x<<std::endl;
}
}
int main(int argc, char* argv[])
{
f(4);
f(argc);
return 0;
}
x
不是常量表达式,无论 f
本身如何求值。那是一个常规的 if
就在那里(is_constant_evaluated
是如何使用的)。它不是一个废弃的分支,所以它必须包含格式正确的代码,即使 f
是 not 常量评估。当 x
不是常量表达式时,该函数仍将包含该(未执行的)分支,并且它将尝试在需要常量表达式的地方使用 x
。这显然是错误的。
GCC 不接受是非常正确的。
这里的根本问题是,即使在持续评估期间(以及在 is_constant_evaluated
检查下)调用了 constexpr
(甚至 consteval
)函数,仍然存在只有 一个 函数在所有参数值之间共享。因此,你不能永远将函数参数用作常量表达式(即使使用该参数的调用是一个常量表达式)。如果你想要一个常量表达式参数,它必须是一个模板参数。
更新
找了个小帮手解决了class(当然可以用std::integral_constant
)
template<auto val_>
struct val
{
static constexpr auto value=val_;
};
template<auto v>
struct dummy_stringify
{
static constexpr auto str=v==4 ? "4" : "31"; // this is just an example; imagine here a much more complex logic
};
#include <iostream>
using namespace std;
template<class T>
constexpr void f(T x)
{
if constexpr(requires{ T::value; })
{
std::puts("A compile time calculation:");
std::puts(dummy_stringify<T::value>::str);
} else
{
std::cout<<"A runtime calculation:"<<std::endl;
std::cout<<x<<std::endl;
}
}
int main(int argc, char* argv[])
{
f(val<4>{});
f(argc);
return 0;
}
可以通过 template<char...> auto operator""_v();
到 f(4_v)
进行改进
我已经阅读了 std::is_constant_evaluated()
的定义,但我仍然不确定为什么 (1) 不能使用 最新的 GCC:error: 'x' is not a constant expression
template<auto v>
struct s
{};
constexpr void f(int x)
{
if (std::is_constant_evaluated())
{
// constexpr int z=x; (1)
// s<x> a; (2)
}
}
int main(int argc, char* argv[])
{
f(4);
//f(argc);
return 0;
}
- 按照标准,这应该行得通吗?
- 或者只是 GCC 实现有问题?
- 我能以某种方式实现预期的行为吗?基本上是:
分支在 std::is_constant_evaluated()
- 如果为真:代码可以使用变量作为 constexpr(如 (2))
- 如果为假:代码使用变量作为非constexpr
更新
我可以'transport'将constexpr-essiveness信息放入函数中吗?基本上是在 f()
中决定是否用 constexpr
x 调用它。
更新 关于我想要实现的更复杂的示例:如果可能,此示例应在编译时将参数字符串化。
template<auto v>
struct dummy_stringify
{
static constexpr auto str=v==4 ? "4" : "31"; // this is just an example; imagine here a much more complex logic
};
constexpr void f(int x)
{
if (std::is_constant_evaluated())
{
std::puts("A compile time calculation:");
//std::puts(dummy_stringify<x>::str);
} else
{
std::cout<<"A runtime calculation:"<<std::endl;
std::cout<<x<<std::endl;
}
}
int main(int argc, char* argv[])
{
f(4);
f(argc);
return 0;
}
x
不是常量表达式,无论 f
本身如何求值。那是一个常规的 if
就在那里(is_constant_evaluated
是如何使用的)。它不是一个废弃的分支,所以它必须包含格式正确的代码,即使 f
是 not 常量评估。当 x
不是常量表达式时,该函数仍将包含该(未执行的)分支,并且它将尝试在需要常量表达式的地方使用 x
。这显然是错误的。
GCC 不接受是非常正确的。
这里的根本问题是,即使在持续评估期间(以及在 is_constant_evaluated
检查下)调用了 constexpr
(甚至 consteval
)函数,仍然存在只有 一个 函数在所有参数值之间共享。因此,你不能永远将函数参数用作常量表达式(即使使用该参数的调用是一个常量表达式)。如果你想要一个常量表达式参数,它必须是一个模板参数。
更新
找了个小帮手解决了class(当然可以用std::integral_constant
)
template<auto val_>
struct val
{
static constexpr auto value=val_;
};
template<auto v>
struct dummy_stringify
{
static constexpr auto str=v==4 ? "4" : "31"; // this is just an example; imagine here a much more complex logic
};
#include <iostream>
using namespace std;
template<class T>
constexpr void f(T x)
{
if constexpr(requires{ T::value; })
{
std::puts("A compile time calculation:");
std::puts(dummy_stringify<T::value>::str);
} else
{
std::cout<<"A runtime calculation:"<<std::endl;
std::cout<<x<<std::endl;
}
}
int main(int argc, char* argv[])
{
f(val<4>{});
f(argc);
return 0;
}
可以通过 template<char...> auto operator""_v();
到 f(4_v)