【问题标题】:Typename Keyword for SFINAE [duplicate]SFINAE的类型名关键字[重复]
【发布时间】:2020-02-27 05:35:08
【问题描述】:

我正在研究现代 C++ 中的 SFINAE,我看到以下代码:

#include <iostream>

struct Bar
{
    typedef double it;
};

template <typename T>
typename T::it Foo(const T& arg_f) {
    std::cout << "Foo<T>" << std::endl;
    return 0;
}

int Foo(int i) { std::cout << "foo(int)" << std::endl; return 0; }

int main(int argc, const char* argv[])
{
    Foo(Bar());
    Foo(0);

    return 0;
}
  1. 为什么在这段代码中,开发人员使用类型名 T::it?
  2. 该类型名称与 Bar 的结构有何关系?因为它变量只是在 bar 结构中定义,但它在结构之外用于函数声明。
  3. 什么是 SFINAE?

【问题讨论】:

    标签: c++ visual-c++ metaprogramming sfinae


    【解决方案1】:

    这里使用了关键字typename,因为您正在访问模板类型参数的类型成员。

    除了如果TBar 那么它应该公开一个it 类型成员以获得对重载的访问权限之外,这完全不相关。

    替换失败不是错误是一种模板元编程模式,它依赖于“删除”无法编译的重载

    【讨论】:

      【解决方案2】:

      在您放在这里的模板函数中,开发人员间接指定 Foo 只是一个与 Bar 结构(或其派生实例)一起使用的函数。所以如果你像Foo(Bar())一样实例化它,编译器推导出的模板函数如下:

      Bar::it Foo(const Bar& arg_f) {
          std::cout << "Foo<T>" << std::endl;
          return 0;
      }
      

      但是如果我们将一个整数值而不是 Bar 对象传递给函数,它将像下面的代码一样被实例化:

      int::it Foo(const int& arg_f) {
          std::cout << "Foo<T>" << std::endl;
          return 0;
      }
      

      它有一个错误的实现,结果编译器会失败,因为 int 类没有它的成员。

      但是,如果你想处理这个问题,你应该为 int 值重载 foo 函数,如下所示:

      int Foo(int arg_f)
      {
           std::cout << "Foo<int>" << std::endl;
           return arg_f;
      }
      

      或者您可以使用 enable_if_t 来为浮点或 ... 等特殊数据类型启用模板函数:

      template <typename T>
      typename std::enable_if_t<std::is_floating_point<T>::value, T> Foo(T t)
      {
          std::cout << "Foo<floating point>" << std::endl;
          return t;
      }
      

      另外,我应该澄清类型名称只是在值和类型之间有所不同。当您使用它时,编译器将该对象视为一种类型,而不是一个值,因此开发人员使用它来让编译器知道它是一种类型,而不是一个值。

      另外,正如@Vivick 所说,替换失败不是错误是一种模板元编程模式,它依赖于“删除”无法编译的重载。不过,维基百科对 SFINAE 有很好的参考:https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error

      【讨论】:

        猜你喜欢
        • 2023-03-28
        • 1970-01-01
        • 2015-06-27
        • 2013-10-14
        • 1970-01-01
        • 1970-01-01
        • 2010-09-08
        • 2011-10-01
        • 2011-07-28
        相关资源
        最近更新 更多