为什么SFINAE似乎不适用于nullptr重载?

时间:2016-04-12 14:25:03

标签: c++ sfinae

我试图从一个没有来自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的意思吗?我该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

成员初始化列表不是所谓的“直接上下文”的一部分。 SFINAE只保护这一直接背景。

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

答案 1 :(得分:0)

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),这不存在。并且没有从int转换为nullptr_t