首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果警员对sfinae

如果警员对sfinae
EN

Stack Overflow用户
提问于 2019-01-06 20:06:24
回答 2查看 2.8K关注 0票数 11

随着if constexprc++17中的引入,c++14/c++11中使用编译时SFINAE可以解决的一些问题现在可以用if constexpr来解决,语法更加简单。

例如,考虑以下编译时递归的基本示例,以生成输出可变数量参数的子例程。

代码语言:javascript
复制
#include <iostream>
#include <type_traits>

template <typename T>
void print_sfinae(T&& x)
{
  std::cout << x << std::endl;
}

template <typename T0, typename... T>
std::enable_if_t<(sizeof...(T) > 0)> print_sfinae(T0&& x, T&&... rest)
{
  std::cout << x << std::endl;
  print_sfinae(std::forward<T>(rest)...);
}

template <typename T0, typename... T>
void print_ifconstexpr(T0&&x, T&&... rest)
{
  if constexpr (sizeof...(T) > 0)
         {
            std::cout << x << std::endl;
            print_ifconstexpr(std::forward<T>(rest)...);
         }
  else
      std::cout << x << std::endl;
}

int main()
{
  print_sfinae(5, 2.2, "hello");
  print_ifconstexpr(5, 2.2, "hello");

  return 0;
}

常规print_sfinae使用来自c++11的SFINAE技术,而print_ifconstexpr通过使用if constexpr完成相同的工作。

是否可以假设编译器在计算if constexpr时完全放弃了未经验证的条件,而只为满足if constexpr条件的分支生成代码?标准是否为编译器指定了这样的行为?

更普遍地说,在效率和生成代码方面,基于if constexpr的解决方案是否与基于pre++17 SFINAE的等效解相同?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-01-06 20:18:59

是否可以假设编译器在计算if constexpr时完全放弃了未经验证的条件,而只为满足if constexpr条件的分支生成代码?标准是否为编译器指定了这样的行为?

该标准指定,从[stmt.if]

如果if语句的形式是if constexpr,则条件的值应该是一个经过上下文转换的bool类型的常量表达式;这个表单被称为if constexpr语句。如果转换条件的值为false,则第一个子语句是一个丢弃语句,否则第二个子语句(如果存在)是一个丢弃语句。在包围模板实体的实例化过程中,如果条件在实例化后不依赖于值,则丢弃的子语句(如果有的话)不会被实例化。

这里的要点是,丢弃语句不是实例化的--这是if constexpr作为一种语言特性的全部目的,它允许您编写:

代码语言:javascript
复制
template <typename T0, typename... T>
void print_ifconstexpr(T0&& x, T&&... rest)
{
    std::cout << x << std::endl;
    if constexpr (sizeof...(T) > 0) {
        print_ifconstexpr(std::forward<T>(rest)...);
    }
}

使用简单的if无法做到这一点,因为这仍然需要实例化子语句--即使在编译时条件可以被确定为false。一个简单的if需要调用print_ifconstexpr()的能力。

if constexpr不会实例化递归调用,除非rest...中有某些内容,所以这是可行的。

其他的一切都是由于缺少实例化而产生的。不能为丢弃的语句生成任何代码。

if constexpr表单更易于编写、更易于理解,而且编译速度肯定更快。肯定更喜欢。

注意,您的第一个示例根本不需要SFINAE。这样做很好:

代码语言:javascript
复制
template <typename T>
void print(T&& x)
{
    std::cout << x << std::endl;
}

template <typename T0, typename... T>
void print(T0&& x, T&&... rest)
{
    std::cout << x << std::endl;
    print(std::forward<T>(rest)...);
}

与以下情况一样:

代码语言:javascript
复制
void print() { }

template <typename T0, typename... T>
void print(T0&& x, T&&... rest)
{
    std::cout << x << std::endl;
    print(std::forward<T>(rest)...);
}
票数 10
EN

Stack Overflow用户

发布于 2019-01-06 23:03:17

C++指定程序可观察的行为。

这两段代码都具有可观察的行为打印。

复制引用,调用接受引用并返回无效的函数,都是不可观察的行为。

这两种功能都有相同的明显行为。因此,C++标准有必要说明它们之间在运行时、代码大小或内存使用方面的任何差异。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54065446

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档