这些 if 语句会在编译时解析吗?

Will those if statements be resolved at compile time?

本文关键字:编译 if 语句 这些      更新时间:2023-10-16

嘿伙计们,我有几个问题无法自己回答。

void someFunc_1(some_known_type_1 bar);
void someFunc_2(some_known_type_2 bar);
void someFunc_3(some_known_type_3 bar);
template < class T, T success> 
void foo(T check) {
// ...
auto bar = check;
if (std::is_same<T, some_known_type_1>::value) {
someFunc_1((some_known_type_1) bar);
// ... 
}
else if (std::is_same<T, some_known_type_2>::value) {
someFunc_2((some_known_type_2) bar);
// ... 
}
else if (std::is_same<T, some_known_type_3>::value) {
someFunc_3((some_known_type_3) bar);
// ... 
}
// ...
}

上面的代码是我的模板函数的最简单版本,用于识别//处理错误。我以这种方式编写此函数以避免代码重复 - 如果我必须使用模板专用化,我会发现在每个版本中代码的一部分都是重复的。

问题:
1.这些 if 语句会在编译时解析吗?我认为他们会,但我不确定。代码正在编译我测试了它。
2. 正常 如果我不使用变量auto bar我最终会为每个 if 语句出现编译时错误(类型不匹配)。因此auto使用变量是个好主意吗?还是有更好的?(我也尝试使用函数指针,它有效,但它对性能不友好)





编辑:
1.好吧,你们中的很多人告诉我,我可以超载someFunc,所以我这样做了。但我现在有一个新的问题:调用空虚空函数是否明智?

新版本的代码

///////////////////////////////////
// someFunc:
// - this function in my original code handles different kinds of errors.
// - overloaded for 2 different types (some_known_type_1 & some_known_type_2).
// - with "Catch-all do-nothing" template. 
inline void someFunc (some_known_type_1 bar) {
// Do something...
}
inline void someFunc (some_known_type_2 bar) {
// Do something...
}
// Catch-all do-nothing:
template <class T>
inline void someFunc(const T& bar) { /* I am empty... */ };
///////////////////////////////////
// Errchk: (Error check)
template < class T, T success> inline
void errchk(T check) {
if (check != success) {
std::cout << "there was an error !!!" << std::endl;
// Handle Error:
someFunc( check );
}
}
// Few additional macros to simplify call to errchk function:
#define ERRCHK_BOOL(_check)   errchk <bool, true> (_check);
#define ERRCHK_TYPE_1(_check) errchk <some_known_type_1, type_1_success_value> (_check);
#define ERRCHK_TYPE_2(_check) errchk <some_known_type_2, type_2_success_value> (_check);
///////////////////////////////////
// program main function:
int main() {
bool error = false; // this value will be recognized as an error by errchk function;
ERRCHK_BOOL(error);
some_known_type_1 error_1 = type_1_error_value // same...
ERRCHK_TYPE_1(error_1);
some_known_type_2 error_2 = type_2_error_value // same...
ERRCHK_TYPE_2(error_2);
}

好的,所以如果你仔细观察,你会发现我没有重载 bool 类型的someFunc,因此每次我使用ERRCHK_BOOL(***);我都会调用someFunc模板的非专用版本,这基本上是对空函数的调用。调用空函数是个好主意吗?

C++17中,您可以使用constexpr if来确保;

如果您无法访问 C++17,仍然有一些 SFINAE 技巧(例如,您可以在一些虚拟的额外参数上重载您的函数)可以完成这项工作,但无论如何,您的if语句很可能会在编译时得到解决。

至于auto bar部分,问题有点不清楚。在这里使用auto似乎完全正常,尽管它与T bar完全相同。

我不得不说,虽然一个简单的模板专业化可以更清楚地完成相同的工作:

void someFunc_1(some_known_type_1 bar);
void someFunc_2(some_known_type_2 bar);
void someFunc_3(some_known_type_3 bar);
template < class T, T success> 
void foo(T check) {
// ...
}
template <some_known_type_1 success> 
void foo<some_known_type_1, success>(some_known_type_1 check) {
someFunc_1(check);
// ... 
}

从您的代码中不清楚 -success参数有点碍事 - 但也许甚至函数重载就足够了(正如其他人指出的那样)。

您正在执行的操作看起来像手动重新创建函数重载系统。让编译器承受压力:

void someFunc(some_known_type_1 bar);
void someFunc(some_known_type_2 bar);
void someFunc(some_known_type_3 bar);
template < class T, T success> 
void foo(T check) {
someFunc(check);
// ...
}

是的,因为Tsome_known_type_1在编译时是已知的,所以现代编译器将优化if语句。原因是:几十年来,它们的设计目的是检测死代码分支并消除它们。如果您没有启用任何编译器优化,那么出于同样的原因,答案是否定的。

auto

在那个上下文中不太有意义,因为你正在处理泛型代码,请改用T bar = check;

您未使用的分支可能会被优化(至少 clang/gcc 可以这样做 - https://gcc.godbolt.org/在线检查),正如其他人在即将到来的 C++17 中指出的那样constexpr if将是此类编译时任务的首选。

最后通知:由于没有完全了解您的代码,我真的不能说,但仅从该片段来看,您似乎正在重新发明类型重载或模板专用化。你应该退后一步,考虑更大的图景。