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