为什么 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)
,它不存在。并且没有从 int
到 nullptr_t
. 的转换
成员初始化列表不是所谓的"immediate context"的一部分。只有这个直接上下文由 SFINAE 保护。
除此之外,SFINAE 仅保护不属于函数体(定义部分)的函数声明部分的替换。成员初始化列表属于构造函数体。这个主体是从声明中独立实例化的,这里的任何错误都是致命的。
我正在尝试从 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)
,它不存在。并且没有从int
到nullptr_t
. 的转换
成员初始化列表不是所谓的"immediate context"的一部分。只有这个直接上下文由 SFINAE 保护。
除此之外,SFINAE 仅保护不属于函数体(定义部分)的函数声明部分的替换。成员初始化列表属于构造函数体。这个主体是从声明中独立实例化的,这里的任何错误都是致命的。