当前位置: 首页 > news >正文

娱乐网站设计SEO网站处于建设中会显示什么英文

娱乐网站设计SEO,网站处于建设中会显示什么英文,老牌深圳公司大雨中解散,南阳网站建设费用编译期if语句 if constexpr 编译期if语句使用编译期if语句编译期if的注意事项编译期if影响返回值类型即使在 *then* 部分返回也要考虑 *else* 部分编译期短路求值 其他编译期if的示例完美返回泛型值使用编译期if进行类型分发 带初始化的编译期if语句在模板之外使用编译期if参考… 编译期if语句 if constexpr 编译期if语句使用编译期if语句编译期if的注意事项编译期if影响返回值类型即使在 *then* 部分返回也要考虑 *else* 部分编译期短路求值 其他编译期if的示例完美返回泛型值使用编译期if进行类型分发 带初始化的编译期if语句在模板之外使用编译期if参考 通过使用语法if constexpr(...)编译器可以计算编译期的条件表达式来在编译期决定使用一个if语句的 then 的部分还是 else 的部分。其余部分的代码将会被丢弃这意味着它们甚至不会被生成。然而这并不意味着被丢弃的部分完全被忽略这些部分中的代码也会像没使用的模板一样进行语法检查。 例如 #include stringtemplate typename T std::string asString(T x) {if constexpr(std::is_same_vT, std::string) {return x; // 如果T不能自动转换为string该语句将无效}else if constexpr(std::is_arithmetic_vT) {return std::to_string(x); // 如果T不是数字类型该语句将无效}else {return std::string(x); // 如果不能转换为string该语句将无效} }通过使用if constexpr我们在编译期就可以决定我们是简单返回传入的字符串、对传入的数字调用to_string()还是使用构造函数来把传入的参数转换为std::string。无效的调用将被 丢弃 因此下面的代码能够通过编译如果使用运行时if语句则不能通过编译 #include iostreamint main() {std::cout asString(42) \n;std::cout asString(std::string(hello)) \n;std::cout asString(hello) \n; }预编译代码如下 //代码std::cout asString(42) \n;的预编译代码如下 /* First instantiated from: insights.cpp:19 */ #ifdef INSIGHTS_USE_TEMPLATE template std::basic_stringchar, std::char_traitschar, std::allocatorchar asStringint(int x) {if constexpr(false) {} else /* constexpr */ {if constexpr(true) {return std::to_string(x);} } } #endif//代码std::cout asString(std::string(hello)) \n;的预编译代码如下 /* First instantiated from: insights.cpp:20 */ #ifdef INSIGHTS_USE_TEMPLATE template std::basic_stringchar, std::char_traitschar, std::allocatorchar asStringstd::basic_stringchar, std::char_traitschar, std::allocatorchar (std::basic_stringchar, std::char_traitschar, std::allocatorchar x) {if constexpr(true) {return std::basic_stringchar, std::char_traitschar, std::allocatorchar (static_caststd::basic_stringchar, std::char_traitschar, std::allocatorchar (x));} } #endif//代码std::cout asString(hello) \n;的预编译代码如下 /* First instantiated from: insights.cpp:21 */ #ifdef INSIGHTS_USE_TEMPLATE template std::basic_stringchar, std::char_traitschar, std::allocatorchar asStringconst char *(const char * x) {if constexpr(false) {} else /* constexpr */ {if constexpr(false) {} else /* constexpr */ {return std::basic_stringchar, std::char_traitschar, std::allocatorchar (std::basic_stringchar, std::char_traitschar, std::allocatorchar (x, std::allocatorchar()));} } } #endifint main() {std::operator(std::operator(std::cout, asString(42)), \n);std::operator(std::operator(std::cout, asString(std::basic_stringchar, std::char_traitschar, std::allocatorchar (std::basic_stringchar, std::char_traitschar, std::allocatorchar (hello, std::allocatorchar())))), \n);std::operator(std::operator(std::cout, asString(hello)), \n);return 0; }编译期if语句 如果我们在上面的例子中使用运行时if下面的代码将永远不能通过编译 #include stringtemplate typename T std::string asString(T x) {if (std::is_same_vT, std::string) {return x; // 如果不能自动转换为string会导致ERROR}else if (std::is_numeric_vT) {return std::to_string(x); // 如果不是数字将导致ERROR}else {return std::string(x); // 如果不能转换为string将导致ERROR} } 这是因为模板在实例化时整个模板会作为一个整体进行编译。然而if语句的条件表达式的检查是运行时特性。即使在编译期就能确定条件表达式的值一定是false then 的部分也必须能通过编译。因此当传递一个std::string或者字符串字面量时会因为std::to_string()无效而导致编译失败。此外当传递一个数字值时将会因为第一个和第三个返回语句无效而导致编译失败。 使用编译期if语句时 then 部分和 else 部分中不可能被用到的部分将成为 丢弃的语句 当传递一个std::string时第一个if语句的 else 部分将被丢弃。 template std::basic_stringchar, std::char_traitschar, std::allocatorchar asStringstd::basic_stringchar, std::char_traitschar, std::allocatorchar (std::basic_stringchar, std::char_traitschar, std::allocatorchar x) {if constexpr(true) {return std::basic_stringchar, std::char_traitschar, std::allocatorchar (static_caststd::basic_stringchar, std::char_traitschar, std::allocatorchar (x));} }当传递一个数字时第一个if语句的 then 部分和最后的 else 部分将被丢弃。 #ifdef INSIGHTS_USE_TEMPLATE template std::basic_stringchar, std::char_traitschar, std::allocatorchar asStringint(int x) {if constexpr(false) {} else /* constexpr */ {if constexpr(true) {return std::to_string(x);} } } #endif当传递一个字符串字面量类型为const char*时第一和第二个if语句的 then 部分将被丢弃。 #ifdef INSIGHTS_USE_TEMPLATE template std::basic_stringchar, std::char_traitschar, std::allocatorchar asStringconst char *(const char * x) {if constexpr(false) {} else /* constexpr */ {if constexpr(false) {} else /* constexpr */ {return std::basic_stringchar, std::char_traitschar, std::allocatorchar (std::basic_stringchar, std::char_traitschar, std::allocatorchar (x, std::allocatorchar()));} } } #endif因此在每一个实例化中无效的分支都会在编译时被丢弃所以代码能成功编译。注意被丢弃的语句并不是被忽略了。即使是被忽略的语句也必须符合正确的语法并且所有和模板参数无关的调用也必须正确。事实上模板编译的第一个阶段 定义期间 将会检查语法和所有与模板无关的名称是否有效。所有的static_asserts也必须有效即使所在的分支没有被编译。 例如 templatetypename T void foo(T t) {if constexpr(std::is_integral_vT) {if (t 0) {foo(t-1); // OK}}else {undeclared(t); // 如果未被声明且未被丢弃将导致错误undeclared(); // 如果未声明将导致错误即使被丢弃也一样static_assert(false, no integral); // 总是会进行断言即使被丢弃也一样} }对于一个符合标准的编译器来说上面的例子 永远 不能通过编译,报错如下 source:17:9: error: there are no arguments to undeclared that depend on a template parameter, so a declaration of undeclared must be available [-fpermissive]17 | undeclared(); // 如果未声明将导致错误即使被丢弃也一样| ^~~~~~~~~~ source:17:9: note: (if you use -fpermissive, G will accept your code, but allowing the use of an undeclared name is deprecated) source:18:23: error: static assertion failed: no integral18 | static_assert(false, no integral); // 总是会进行断言即使被丢弃也一样原因有两个 即使T是一个整数类型如下调用 undeclared(); // 如果未声明将导致错误即使被丢弃也一样如果该函数未定义时即使处于被丢弃的 else 部分也会导致错误因为这个调用并不依赖于模板参数。 如下断言 static_assert(false, no integral); // 总是会进行断言即使被丢弃也一样即使处于被丢弃的 else 部分也总是会断言失败因为它也不依赖于模板参数。一个使用编译期条件的静态断言没有这个问题 static_assert(!std::is_integral_vT, no integral);注意有一些编译器例如Visual C 2013和2015并没有正确实现模板编译的两个阶段。它们把第一个阶段 定义期间 的大部分工作推迟到了第二个阶段 实例化期间 因此有些无效的函数调用甚至一些错误的语法都可能通过编译。 使用编译期if语句 理论上讲只要条件表达式是编译期的表达式你就可以像使用运行期if一样使用编译期if。你也可以混合使用编译期和运行期的if if constexpr (std::is_integral_vstd::remove_reference_tT) {if (val 10) {if constexpr (std::numeric_limitschar::is_signed) {...}else {...}}else {...} } else {... }注意你不能在函数体之外使用if constexpr。因此你不能使用它来替换预处理器的条件编译。 编译期if的注意事项 使用编译期if时可能会导致一些并不明显的后果。 编译期if影响返回值类型 编译期if可能会影响函数的返回值类型。例如下面的代码总能通过编译但返回值的类型可能会不同 auto foo() {if constexpr (sizeof(int) 4) {return 42;}else {return 42u;} }这里因为我们使用了auto返回值的类型将依赖于返回语句而执行哪条返回语句又依赖于int的字节数 如果大于4字节返回42的返回语句将会生效因此返回值类型是int。否则返回42u的返回语句将生效因此返回值类型是unsigned int。 预处理代码如下 unsigned int foo() {if constexpr(false) {return 42;} else /* constexpr */ {return 42U;} }这种情况下有if constexpr语句的函数可能返回完全不同的类型。例如如果我们不写 else 部分返回值将会是int或者void auto foo() // 返回值类型可能是int或者void {if constexpr (sizeof(int) 4) {return 42;} }预处理代码如下 void foo() {if constexpr(false) {return 42;} } //或者 int foo() {if constexpr(true) {return 42;} }注意这里如果使用运行期if那么代码将永远不能通过编译因为推导返回值类型时会考虑到所有可能的返回值类型因此推导会有歧义。 例如 #include iostream #include string #include utilityusing namespace std;auto foo() {if (sizeof(int) 4) {return 42;} else {return 42u;} }int main() { return 0; }会有如下报错 source:13:16: error: inconsistent deduction for auto return type: int and then unsigned int13 | return 42u;| ^~~即使在 then 部分返回也要考虑 else 部分 运行期if有一个模式不能应用于编译期if如果代码在 then 和 else 部分都会返回那么在运行期if中你可以跳过else部分。也就是说 if (...) {return a; } else {return b; }可以写成 if (...) {return a; } return b;但这个模式不能应用于编译期if因为在第二种写法里返回值类型将同时依赖于两个返回语句而不是依赖其中一个这会导致行为发生改变。例如如果按照上面的示例修改代码那么 也许能也许不能 通过编译 auto foo() {if constexpr (sizeof(int) 4) {return 42;}return 42u; }如果条件表达式为trueint大于4字节编译器将会推导出两个不同的返回值类型这会导致错误。否则将只会有一条有效的返回语句因此代码能通过编译。 可能的报错如下 source:11:12: error: inconsistent deduction for auto return type: int and then unsigned int11 | return 42u;| ^~~编译期短路求值 考虑如下代码 templatetypename T constexpr auto foo(const T val) {if constexpr(std::is_integralT::value) {if constexpr (T{} 10) {return val * 2;}}return val; }这里我们使用了两个编译期条件来决定是直接返回传入的值还是返回传入值的两倍。 下面的代码都能编译 constexpr auto x1 foo(42); // 返回84 constexpr auto x2 foo(hi); // OK返回hi预处理代码如下 #ifdef INSIGHTS_USE_TEMPLATE template inline constexpr int fooint(const int val) {if constexpr(true) {if constexpr(true) {return val * 2;} } return val; } #endif#ifdef INSIGHTS_USE_TEMPLATE template inline constexpr const char * foochar[3](const char (val)[3]) {if constexpr(false) {} return val; } #endifint main() {constexpr const int x1 foo(42);constexpr const char *const x2 foo(hi);return 0; }运行时if的条件表达式会进行短路求值当左侧为false时停止求值当||左侧为true时停止求值。这可能会导致你希望编译期if也会短路求值 templatetypename T constexpr auto bar(const T val) {if constexpr (std::is_integralT::value T{} 10) {return val * 2;}return val; }然而编译期if的条件表达式总是作为整体实例化并且必须整体有效这意味着如果传递一个不能进行10运算的类型将不能通过编译 constexpr auto x2 bar(hi); // 编译期ERROR报错信息如下 source: In instantiation of constexpr auto bar(const T) [with T char [3]]: source:17:28: required from here source:10:53: error: taking address of temporary array10 | if constexpr (std::is_integralT::value T{} 10) {| ~~~~^~~~ source:11:20: error: invalid operands of types const char [3] and int to binary operator*11 | return val * 2;| ~~~~^~~ source: In function int main(): source:17:28: error: constexpr auto bar(const T) [with T char [3]] called in a constant expression17 | constexpr auto x2 bar(hi);| ~~~^~~~~~ source:8:16: note: constexpr auto bar(const T) [with T char [3]] is not usable as a constexpr function because:8 | constexpr auto bar(const T val)| 因此编译期if在实例化时并不短路求值。如果后边的条件的有效性依赖于前边的条件那你需要把条件进行嵌套。例如你必须写成如下形式 if constexpr (std::is_same_vMyType, T) {if constepxr (T::i 42) {...} }而不是写成 if constexpr (std::is_same_vMyType, T T::i 42) {... }其他编译期if的示例 完美返回泛型值 编译期if的一个应用就是先对返回值进行一些处理再进行完美转发。因为decltype(auto)不能推导为void因为void是不完全类型所以你必须像下面这么写 #include functional // for std::forward() #include functional // for std::forward() #include iostream #include type_traits // for std::is_same and std::invoke_resultusing namespace std;double foo1(int x, int y) { return x * 2.5 y; } void foo2() { cout foo2 endl; }template typename Callable, typename... Args decltype(auto) call(Callable op, Args... args) {if constexpr (std::is_void_vstd::invoke_result_tCallable, Args...) {// 返回值类型是voidop(std::forwardArgs(args)...);return;} else {// 返回值类型不是void:decltype(auto) ret{op(std::forwardArgs(args)...)};return ret;} } int main() {double tv1 call(foo1, 5, 3);cout tv1 endl;call(foo2);return 0; }函数的返回值类型可以推导为void但ret的声明不能推导为void因此必须把op返回void的情况单独处理。 运行结果如下 15.5 foo2预编译代码如下 #include functional // for std::forward() #include iostream #include type_traits // for std::is_same and std::invoke_resultusing namespace std;double foo1(int x, int y) {return (static_castdouble(x) * 2.5) static_castdouble(y); }void foo2() {std::operator(std::cout, foo2).operator(std::endl); }templatetypename Callable, typename ... Args decltype(auto) call(Callable op, Args ... args) {if constexpr(std::is_void_vstd::invoke_result_tCallable, Args... ) {op(std::forwardArgs(args)... );return;} else /* constexpr */ {decltype(auto) ret {op(std::forwardArgs(args)... )};return ret;} }#ifdef INSIGHTS_USE_TEMPLATE template double calldouble (*)(int, int), int, int(double (*op)(int, int), int __args1, int __args2) {if constexpr(false) {} else /* constexpr */ {double ret {op(std::forwardint(__args1), std::forwardint(__args2))};return ret;} } #endif#ifdef INSIGHTS_USE_TEMPLATE template void callvoid (*)()(void (*op)()) {if constexpr(true) {op();return;} } #endifint main() {double tv1 call(foo1, 5, 3);std::cout.operator(tv1).operator(std::endl);call(foo2);return 0; }使用编译期if进行类型分发 编译期if的一个典型应用是类型分发。在C17之前你必须为每一个想处理的类型重载一个单独的函数。现在有了编译期if你可以把所有的逻辑放在一个函数里。 例如如下的重载版本的std::advance()算法 templatetypename Iterator, typename Distance void advance(Iterator pos, Distance n) {using cat std::iterator_traitsIterator::iterator_category;advanceImpl(pos, n, cat{}); // 根据迭代器类型进行分发 }templatetypename Iterator, typename Distance void advanceImpl(Iterator pos, Distance n, std::random_access_iterator_tag) {pos n; }templatetypename Iterator, typename Distance void advanceImpl(Iterator pos, Distance n, std::bidirectional_iterator_tag) {if (n 0) {while (n--) {pos;}}else {while (n) {--pos;}} }templatetypename Iterator, typename Distance void advanceImpl(Iterator pos, Distance n, std::input_iterator_tag) {while (n--) {pos;} }现在可以把所有实现都放在同一个函数中 templatetypename Iterator, typename Distance void advance(Iterator pos, Distance n) {using cat std::iterator_traitsIterator::iterator_category;if constexpr (std::is_convertible_vcat, std::random_access_iterator_tag) {pos n;}else if constexpr (std::is_convertible_vcat, std::bidirectional_access_iterator_tag) {if (n 0) {while (n--) {pos;}}else {while (n) {--pos;}}}else { // input_iterator_tagwhile (n--) {pos;}} }这里我们就像是有了一个编译期switch每一个if constexpr语句就像是一个case。然而注意例子中的两种实现还是有一处不同的 重载函数的版本遵循 最佳匹配 语义。编译期if的版本遵循 最先匹配 语义。 另一个类型分发的例子是使用编译期if实现get()重载来实现结构化绑定接口。 第三个例子是在用作std::variant访问器的泛型lambda中处理不同的类型。 带初始化的编译期if语句 注意编译期if语句也可以使用新的带初始化的形式。例如如果有一个constexpr函数foo()你可以这样写 #include functional // for std::forward() #include iostream #include type_traits // for std::is_same and std::invoke_resultusing namespace std;double foo(int x) { return x * 2.5; }template typename T void bar(const T x) {if constexpr (auto obj foo(x); std::is_same_vdecltype(obj), T) {std::cout foo(x) yields same type\n;} else {std::cout foo(x) yields different type\n;} } int main() {bar(2);bar(2.5);return 0; }运行结果如下 foo(x) yields different type foo(x) yields same type预处理代码如下 #include functional // for std::forward() #include iostream #include type_traits // for std::is_same and std::invoke_resultusing namespace std;double foo(int x) {return static_castdouble(x) * 2.5; }templatetypename T void bar(const T x) {{auto obj foo(x);if constexpr(std::is_same_vdecltype(obj), T) {std::operator(std::cout, foo(x) yields same type\n);} else /* constexpr */ {std::operator(std::cout, foo(x) yields different type\n);} }} /* First instantiated from: insights.cpp:20 */ #ifdef INSIGHTS_USE_TEMPLATE template void barint(const int x) {{double obj foo(x);if constexpr(false) {} else /* constexpr */ {std::operator(std::cout, foo(x) yields different type\n);} } } #endif/* First instantiated from: insights.cpp:21 */ #ifdef INSIGHTS_USE_TEMPLATE template void bardouble(const double x) {{double obj foo(static_castint(x));if constexpr(true) {std::operator(std::cout, foo(x) yields same type\n);} }} #endif int main() {bar(2);bar(2.5);return 0; }如果有一个参数类型也为T的constexpr函数foo()你就可以根据foo(x)是否返回与x相同的类型来进行不同的处理。 如果要根据foo(x)返回的值来进行判定那么可以这么写 #include functional // for std::forward() #include iostream #include type_traits // for std::is_same and std::invoke_resultusing namespace std;constexpr int foo(int x) { return x * 2; }void bar() {constexpr auto c 2;if constexpr (constexpr auto obj foo(c); obj 4) {std::cout foo(c) obj endl;} else {std::cout foo(x) yields different type\n;} } int main() {bar();return 0; }注意如果想在条件语句中使用obj的值那么obj必须要声明为constexpr。运行结果如下 foo(c) 4预处理代码如下 #include functional // for std::forward() #include iostream #include type_traits // for std::is_same and std::invoke_resultusing namespace std;inline constexpr int foo(int x) {return x * 2; }void bar() {constexpr const int c 2;{constexpr const int obj foo(c);if constexpr(true) {std::operator(std::operator(std::operator(std::cout, foo(), c), ) ).operator(obj).operator(std::endl);} else /* constexpr */ {std::operator(std::cout, foo(x) yields different type\n);} } } int main() {bar();return 0; }在模板之外使用编译期if if constexpr可以在任何函数中使用而并非仅限于模板。只要条件表达式是编译期的并且可以转换成bool类型。然而在普通函数里使用时 then 和 else 部分的所有语句都必须有效即使有可能被丢弃。 例如下面的代码不能通过编译因为undeclared()的调用必须是有效的即使char是有符号数导致 else 部分被丢弃也一样 #include limitstemplatetypename T void foo(T t);int main() {if constexpr(std::numeric_limitschar::is_signed) {foo(42); // OK}else {undeclared(42); // 未声明时总是ERROR即使被丢弃} }下面的代码也永远不能成功编译因为总有一个静态断言会失败 if constexpr(std::numeric_limitschar::is_signed) {static_assert(std::numeric_limitschar::is_signed); } else {static_assert(!std::numeric_limitschar::is_signed); }在泛型代码之外使用编译期if的唯一好处是被丢弃的部分不会成为最终程序的一部分这将减小生成的可执行程序的大小。例如在如下程序中 #include limits #include string #include arrayint main() {if (!std::numeric_limitschar::is_signed) {static std::arraystd::string, 1000 arr1;...}else {static std::arraystd::string, 1000 arr2;...} }要么arr1要么arr2会成为最终可执行程序的一部分但不可能两者都是。 参考 http://www.cppstd17.com/
http://www.w-s-a.com/news/205794/

相关文章:

  • 提供做网站公司有哪些关键词优化诊断
  • 建站合肥网络公司seo免费建手机商城网站吗
  • 设计师投资做项目网站外贸网站建设工作室
  • 无聊的网站wordpress的alt属性插件
  • 个股期权系统网站开发小清新wordpress模板
  • 全中文网站开发建筑公司企业愿景文案
  • 广州网站建设正规公司建设银行信用卡中心网站
  • 哪个网站是专门做封面素材怎么制作app平台
  • 网站开发 平均工资商标注册在哪个部门申请
  • 做外贸需要自己的网站吗营销型网站建设市场分析
  • 绍兴网站制作推广wordpress 无法自动升级
  • 阿里云建站数据库用什么app制作开发费用多少
  • 中国住房和城乡建设部网站资质查询中小开网站
  • 交易所网站开发水果营销软文
  • 石家庄有什么好玩的地方2017织梦网站怎么做seo
  • wordpress项目插件seo的含义
  • 网站平台建设的作用电影宣传类网页界面设计
  • 户外网站模板国外优秀的平面设计网站
  • 家政网站怎么做网站机房建设方案
  • 学校网站建设运行情况2022年近期舆情热点话题
  • 做淘宝需要知道什么网站吗有没有做软件的网站
  • 安丘网站建设制作做网站和微信小程序
  • 京东网站的建设与发展前景黑龙江建设网官网登陆
  • soho的网站怎么做微网站平台建设方案
  • 网站开发下载阿里云oss做视频网站
  • 东莞营销网站制作做一个网站建设
  • 啥网站都能看的浏览器下载网站后台管理系统展望
  • 新建站点步骤汉中 wordpress联盟
  • 坪山网站设计的公司网站 seo 设置
  • 济南网站设计公司排名如何免费注册网站域名