为什么 SFINAE 似乎不能在此处使用 nullptr 重载?

Why doesn't SFINAE appear to work with nullptr overload here?

我正在尝试从 class 派生,它没有来自 int 的构造函数,但来自 nullptr,试图使派生的构造函数成为通用的当它需要一个参数时尽可能。但由于某种原因,似乎没有采用正确的构造函数,即使将 int 替换为模板构造函数导致失败:

#include <cstddef>
#include <iostream>

struct Base
{
    Base(std::nullptr_t){}
    Base(){}
    // some other constructors, but not from int
};

struct Test : Base
{
    Test(std::nullptr_t) : Base(nullptr)
    {
        std::cerr << "Test(nullptr)\n";
    }
    template<typename T>
    Test(T v) : Base(v) {}
};

int main()
{
    Base b=0;       // works
    Test z=nullptr; // works
    Test t=0;       // compilation error
}

为什么会这样?这不是 SFINAE 应该表达的意思吗?我该如何解决这个问题?

GCC 告诉我

36576202.cpp: In instantiation of ‘Test::Test(T) [with T = int]’:
36576202.cpp:25:12:   required from here
36576202.cpp:18:23: error: no matching function for call to ‘Base::Base(int&)’
     Test(T v) : Base(v) {}
                       ^
36576202.cpp:18:23: note: candidates are:
36576202.cpp:7:5: note: Base::Base()
     Base(){}
     ^
36576202.cpp:7:5: note:   candidate expects 0 arguments, 1 provided
36576202.cpp:6:5: note: Base::Base(std::nullptr_t)
     Base(std::nullptr_t){}
     ^
36576202.cpp:6:5: note:   no known conversion for argument 1 from ‘int’ to ‘std::nullptr_t’
36576202.cpp:4:8: note: constexpr Base::Base(const Base&)
 struct Base
        ^
36576202.cpp:4:8: note:   no known conversion for argument 1 from ‘int’ to ‘const Base&’
36576202.cpp:4:8: note: constexpr Base::Base(Base&&)
36576202.cpp:4:8: note:   no known conversion for argument 1 from ‘int’ to ‘Base&&’

这表明

  • Test t=0; 通过模板 Test(T),使用 T==int。这是一个有效的替换,因此 SFINAE 不相关。
  • Test(T==int) 然后需要 Base(int),它不存在。并且没有从 intnullptr_t.
  • 的转换

成员初始化列表不是所谓的"immediate context"的一部分。只有这个直接上下文由 SFINAE 保护。

除此之外,SFINAE 仅保护不属于函数体(定义部分)的函数声明部分的替换。成员初始化列表属于构造函数体。这个主体是从声明中独立实例化的,这里的任何错误都是致命的。