SFINAE的类型名称关键字

时间:2019-10-31 20:01:09

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

我正在研究现代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 struct中定义的变量,但在struct之外将其用于函数声明。
  3. 什么是SFINAE?

2 个答案:

答案 0 :(得分:2)

此处使用关键字typename是因为您正在访问模板类型参数的类型成员。

除了TBar的事实之外,它完全不相关,它应该公开一个it类型的成员才能访问重载。

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

答案 1 :(得分:1)

在此处放置的模板函数中,开发人员间接指定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