【问题标题】:decltype(auto) works with SFINAE in some cases?decltype(auto) 在某些情况下与 SFINAE 一起使用?
【发布时间】:2018-07-01 00:24:00
【问题描述】:

我假设decltype(auto) 在用于尝试和 SFINAE 关闭返回类型时是一个不兼容的构造。所以,当你本来会得到一个替换错误时,你会得到一个硬错误

但是为什么下面的程序可以工作? https://wandbox.org/permlink/xyvxYsakTD1tM3yl

#include <iostream>
#include <type_traits>

using std::cout;
using std::endl;

template <typename T>
class Identity {
public:
  using type = T;
};

template <typename T>
decltype(auto) construct(T&&) {
  return T{};
}

template <typename T, typename = std::void_t<>>
class Foo {
public:
  static void foo() {
    cout << "Nonspecialized foo called" << endl;
  }
};
template <typename T>
class Foo<T,
          std::void_t<typename decltype(construct(T{}))::type>> {
public:
  static void foo() {
    cout << "Specialized foo called" << endl;
  }
};

int main() {
  Foo<Identity<int>>::foo();
  Foo<int>::foo();
}

Fooint 实例化时,我们不应该得到一个硬错误吗?鉴于 int 没有名为 type 的成员别名?

【问题讨论】:

    标签: c++ c++17 sfinae


    【解决方案1】:

    我假设 decltype(auto) 在用于尝试和 SFINAE 关闭返回类型时是一个不兼容的构造。

    它通常是不兼容的,因为它强制实例化函数体。如果在 body 中发生替换失败,那么这将是一个硬编译错误 - SFINAE 不适用于此处。

    但是,在本例中,如果T 不是默认可构造的,那么您会在正文中出现替换失败的唯一方法。但是您调用 construct(T{}),它已经要求 T 是默认可构造的 - 所以失败将首先发生或永远不会发生。

    相反,发生的替换失败是在替换为typename decltype(construct(T{}))::type 的直接上下文中。尝试从 int 中取出 ::type 发生在我们将模板参数实例化为 Foo 的直接上下文中,因此 SFINAE 仍然适用。

    演示decltype(auto) 破坏 SFINAE 的示例是,如果我们改为将其实现为:

    template <typename T>
    decltype(auto) construct() {
      return T{};
    }
    
    template <typename T, typename = std::void_t<>>
    class Foo {
    public:
      static void foo() {
        cout << "Nonspecialized foo called" << endl;
      }
    };
    template <typename T>
    class Foo<T,
              std::void_t<typename decltype(construct<T>())::type>> {
    public:
      static void foo() {
        cout << "Specialized foo called" << endl;
      }
    };
    

    然后尝试实例化:

    struct X {
        X(int);
    };
    
    Foo<X>::foo(); // hard error, failure is in the body of construct()
    

    【讨论】:

    • 啊,这很有道理!我的理解显然是不完整的。谢谢!为了完整起见,您能否指出标准中的相关部分?
    • 不知何故我在这里仍然没有收到错误 - wandbox.org/permlink/PsV9Z7mlCS8uzppg?
    • @Curious 因为现在T{}首先在直接上下文中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 2011-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多