转发声明的函数和 SFINAE

Dut*_*tow 5 c++ sfinae c++17

我在unconstexpr库中遇到了一个有趣的模式。

根据自述文件,这个想法是给定一个前向声明的自动返回类型函数,在实际定义函数之前不能推断返回类型,这允许一些 SFINAE 魔法。

我认为这个语言特性可能对其他一些想法有用,并用它做了一些实验,当函数不是模板时,看起来 gcc 和 clang 的行为不同:gcc 工作相同,而 clang 报告错误。

根据 clang 的错误消息显示的内容,也许它甚至不适用于模板?

所以问题是:

  • 标准是否允许模板部分(clang 和 gcc 都允许)?
  • 哪个编译器对非模板版本是正确的?

简化代码(也在Godbolt 上):

struct S {};

constexpr auto f1();

template <typename T>
constexpr auto f2(T);

// compilation error with clang:
// function with deduced return type cannot be used before it is defined
template <typename T, typename = decltype(f1())>
void test1_1() {}
template <typename T>
void test1_1() {}

// compiles with clang, even if f2 will never be defined
template <typename T, typename = decltype(f2<T>(T{}))>
constexpr int test1_2(int) { return 1; }
template <typename T>
constexpr int test1_2(float) { return 2; }

/////////////////

int g1_2() {
  return test1_2<S>(0);
}

constexpr auto f1() { return 1; }

// comment-uncomment this:
// the value returned by g2_@ will change
// /*
template <typename T>
constexpr auto f2(T) {
  return 2;
}
// */

// can be defined here
template <typename T, typename = decltype(f1())>
void test2_1() {}

int g2_2() {
  return test1_2<S>(0);
}
Run Code Online (Sandbox Code Playgroud)

注意:最初我还提到它与朋友的行为不同,并且它似乎在没有自动返回类型的情况下工作 - 这些是我的用户错误。