C++ 1z将引入"constexpr if" - 如果将根据条件删除其中一个分支.似乎合理有用.
但是,没有constexpr关键字是不可能的?我认为在编译期间,编译器应该知道编译时间是否已知.如果是,即使是最基本的优化级别也应该删除不必要的分支.
例如(参见godbolt:https://godbolt.org/g/IpY5y5 ):
int test() {
const bool condition = true;
if (condition) {
return 0;
} else {
// optimized out even without "constexpr if"
return 1;
}
}
Run Code Online (Sandbox Code Playgroud)
Godbolt探险家表示,即使是带有-O0的gcc-4.4.7也没有编译"返回1",所以它实现了constexpr所承诺的.显然,当条件是constexpr函数的结果时,这样的旧编译器将无法这样做,但事实仍然存在:现代编译器知道条件是否为constexpr,并且不需要我明确地告诉它.
所以问题是:
为什么"constexpr if"需要"constexpr"?
我已经在C++ 17编译器(Coliru)中编译并运行了以下程序.在程序中,我声明了一个extern
变量,但没有定义它.但是,编译器不会给出链接器错误.
#include <iostream>
extern int i; // Only declaration
int func()
{
if constexpr (true)
return 0;
else if (i)
return i;
else
return -1;
}
int main()
{
int ret = func();
std::cout<<"Ret : "<<ret<<std::endl;
}
Run Code Online (Sandbox Code Playgroud)
为什么编译器没有给出链接器错误?
受此答案的启发,我尝试复制并粘贴(并添加测试main()
)此代码:
template<typename T>
std::tuple<int, double> foo(T a) {
if constexpr (std::is_same_v<int, T>)
return {a, 0.0};
else if (std::is_same_v<double, T>)
return {0, a};
else
return {0, 0.0};
}
int main() {
auto [x, y] = foo("");
std::cout << x << " " << y;
}
Run Code Online (Sandbox Code Playgroud)
这非常简单 - 如果T
推断为int
,我们想要返回一个元组[a, 0.0]
.如果T
推断为double
,我们想要返回一个元组 [0, a]
.否则,我们想要回来[0, 0.0]
.
正如你所看到的,在main()
函数中,我foo
用const char*
参数调用,这应该导致x
和 …
参考这个问题.用于初始化constexpr
变量的核心常量表达式是错误的y
.这么多是给定的.
但如果我试着if
变成if constexpr
:
template <typename T>
void foo() {
constexpr int x = -1;
if constexpr (x >= 0){
constexpr int y = 1 << x;
}
}
int main(){
foo<int>();
}
Run Code Online (Sandbox Code Playgroud)
错误仍然存在.GCC 7.2仍然给出:
error: right operand of shift expression '(1 << -1)' is negative [-fpermissive]
Run Code Online (Sandbox Code Playgroud)
但我认为语义检查应该在废弃的分支上保持不成形.
constexpr
但是,通过lambda 进行间接确实有帮助:
template <typename T>
void foo(){
constexpr int x = -1;
constexpr auto p = []() constexpr { return x; }; …
Run Code Online (Sandbox Code Playgroud) 也许我错过了一些东西,但我找不到任何提示:C++ 17中有一个constexpr三元运算符,相当于constexpr-if?
template<typename Mode>
class BusAddress {
public:
explicit constexpr BusAddress(Address device) :
mAddress(Mode::write ? (device.mDevice << 1) : (device.mDevice << 1) | 0x01) {}
private:
uint8_t mAddress = 0;
};
Run Code Online (Sandbox Code Playgroud) 如何使用概念if constexpr
?
给出下面的例子,if constexpr
如果T
满足要求,则返回1 将给予integral
什么?
template<typename T>
concept integral = std::is_integral_v<T>;
struct X{};
template<typename T>
constexpr auto a () {
if constexpr (/* T is integral */) {
return 1;
}
else {
return 0;
}
}
int main () {
return a<X>();
}
Run Code Online (Sandbox Code Playgroud) 如下代码:
#include <type_traits>
struct X {
static constexpr void x() {}
};
template <class T1, class T2>
constexpr bool makeFalse() { return false; }
template <class T>
void foo() {
T tmp;
auto f = [](auto type) {
if constexpr (makeFalse<T, decltype(type)>()) {
T::x(); // <- clang does not discard
} else {
// noop
}
};
}
int main() {
foo<int>();
}
Run Code Online (Sandbox Code Playgroud)
不使用Clang编译,但是使用GCC编译。我看不到这段代码有什么问题,但是我不确定。Clang对吗?
有没有一种方法可以确定是否可以对constexpr求值,并将结果用作constexpr布尔值?我的简化用例如下:
template <typename base>
class derived
{
template<size_t size>
void do_stuff() { (...) }
void do_stuff(size_t size) { (...) }
public:
void execute()
{
if constexpr(is_constexpr(base::get_data())
{
do_stuff<base::get_data()>();
}
else
{
do_stuff(base::get_data());
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的目标是C ++ 2a。
我发现了以下reddit线程,但我不是宏的忠实拥护者。https://www.reddit.com/r/cpp/comments/7c208c/is_constexpr_a_macro_that_check_if_an_expression/
考虑两个struct
具有不同成员类型别名的s:
struct foo { using x = int; };
struct bar { using y = float; };
Run Code Online (Sandbox Code Playgroud)
给定T
的template
情况下,我想无论是T::x
还是T::y
取决于什么T
是:
template <typename T>
auto s()
{
auto l = [](auto p)
{
if constexpr(p) { return typename T::x{}; }
else { return typename T::y{}; }
};
return l(std::is_same<T, foo>{});
}
int main()
{
s<foo>();
}
Run Code Online (Sandbox Code Playgroud)
g++
编译上面的代码,同时clang++
产生这个错误:
error: no type named 'y' in 'foo'
else { return typename …
Run Code Online (Sandbox Code Playgroud) 这段代码可以在g ++(coliru)中很好地编译,但是在MSVC(Godbolt和我的VS2017)中却不能。
#include <type_traits>
#include <iostream>
template<class T> void f(){
constexpr bool b=std::is_same_v<T,int>; //#1
auto func_x=[&](){
if constexpr(b){ //#error
}else{
}
};
func_x();
}
int main(){
f<int>();
}
Run Code Online (Sandbox Code Playgroud)
(6):错误C2131:表达式未求值为常数
(6):注意:失败是由于在其生命周期之外读取变量导致的
(6):注意:请参见'this'的用法
哪一个(g ++或MSVC)错了?“ 请参阅'this'的用法 ”
是什么??this
在保留编译时保证的同时如何解决呢?
在我的真实情况下,b (#1)
一个复杂的语句取决于其他一些constexpr变量。
c++ ×10
if-constexpr ×10
c++17 ×8
constexpr ×4
c++20 ×2
c++-concepts ×1
extern ×1
if-statement ×1
lambda ×1
sfinae ×1