C++ 模板提取布尔参数



我想从模板参数中提取布尔值,并在代码的其他地方使用该值。(更具体地说,我想要编译时的一个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!

最新更新