我想从模板参数中提取布尔值,并在代码的其他地方使用该值。(更具体地说,我想要编译时的一个if-else)。
template<bool enable_xx>
struct A {
void DoSomething() {
if (enable_xx) {
// do something
} else {
// do something else
}
}
}
我正在使用 C++11,但如果更高版本存在这样的功能C++也请告诉我,谢谢!
C++17 提供了一种使用if constexpr
执行此操作的方法:
template<bool enable_xx>
struct A {
void DoSomething() {
if constexpr(enable_xx) {
// do something
} else {
// do something else
}
}
};
if constexpr
只在编译时运行,它完全按照你想要的方式运行。
嗯,if (enable_xx)
可以在编译时解决。大多数编译器会优化您的函数以防止在运行时检查条件,但您无法确定。
处理此问题的最佳方法是使用if constexpr
,这是一个C++17 功能。它允许您指定 if 语句依赖于一个或多个constexpr
。
给出此代码:
#include <iostream>
template <bool verbose>
void SayHello()
{
if (verbose)
{
std::cout << "Hello guys!n";
}
else
{
std::cout << "Hi!n";
}
}
SayHello<true>()
的反汇编(使用 x64 msvc v19.20)如下所示:
void SayHello<1>(void) PROC ; SayHello<1>, COMDAT
$LN5:
sub rsp, 40 ; 00000028H
xor eax, eax
cmp eax, 1
je SHORT $LN2@SayHello
lea rdx, OFFSET FLAT:$SG31024
lea rcx, OFFSET FLAT:std::basic_ostream<char,std::char_traits<char> > std::cout ; std::cout
call std::basic_ostream<char,std::char_traits<char> > & std::operator<<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> > &,char const *) ; std::operator<<<std::char_traits<char> >
jmp SHORT $LN3@SayHello
$LN2@SayHello:
lea rdx, OFFSET FLAT:$SG31025
lea rcx, OFFSET FLAT:std::basic_ostream<char,std::char_traits<char> > std::cout ; std::cout
call std::basic_ostream<char,std::char_traits<char> > & std::operator<<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> > &,char const *) ; std::operator<<<std::char_traits<char> >
$LN3@SayHello:
add rsp, 40 ; 00000028H
ret 0
如您所见,程序将在运行时评估条件。
对于 C++17if constexpr
(if (verbose)
==>if constexpr (verbose)
),具有相同编译器选项的反汇编如下所示:
void SayHello<1>(void) PROC ; SayHello<1>, COMDAT
$LN3:
sub rsp, 40 ; 00000028H
lea rdx, OFFSET FLAT:$SG31017
lea rcx, OFFSET FLAT:std::basic_ostream<char,std::char_traits<char> > std::cout ; std::cout
call std::basic_ostream<char,std::char_traits<char> > & std::operator<<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> > &,char const *) ; std::operator<<<std::char_traits<char> >
add rsp, 40 ; 00000028H
ret 0
您可以看到if
语句从生成的代码中消失了。编译器对其进行了优化。
您还可以注意,反汇编与此函数的非模板化版本严格相同:
void SayHelloTrue()
{
std::cout << "Hello guys!n";
}
因此,如果可以使用 C++17,请始终将if
指定为constexpr
(如果它们在编译时可评估),以便在调试模式下优化代码(无优化标志)。如果不能使用 C++17,请假定编译器将具有最后决定权,并且会优化或不会优化代码,具体取决于优化标志及其功能。
我共享的反汇编是使用以下方法生成的: https://godbolt.org/
这个网站是一个很好的工具,可以检查编译器(Clang,GCC,MSVC等)如何与您的代码一起行为。
一种可能性如下
#include <iostream>
template<bool isTrue>
struct A;
template<>
struct A<true>
{
void DoSomething()
{
std::cout << "You did it!" << std::endl;
}
};
template<>
struct A<false>
{
void DoSomething()
{
std::cout << "You did not do it!" << std::endl;
}
};
int main(int argc, char** argv)
{
A<true> a;
A<false> b;
a.DoSomething();
b.DoSomething();
return 0;
}
生成以下输出:
You did it!
You did not do it!