在虚函数上使用 enable_if
Using enable_if on virtual functions
#include <type_traits>
class Base {
public:
virtual bool f() {
return true;
}
};
template<typename T>
class Derived : public Base {
std::enable_if_t< std::is_copy_constructible<T>::value, bool > f() override {
return true;
}
std::enable_if_t< !std::is_copy_constructible<T>::value, bool > f() override {
return false;
}
};
以上代码无法编译。出于某种原因我没能理解,编译器在 SFINAE 删除一个函数之前将这两个函数视为相同的重载。
但是,我不明白我将如何解决这个问题。我找到的文档 state 我应该在函数上使用模板。但是,这不起作用,因为该函数本来就是虚拟的。
我尝试通过调用非虚函数来解决问题,但我也无法编译它:
template<typename T>
class Derived : public Base {
virtual bool f() override {
return f_impl();
}
private:
template< std::enable_if_t< std::is_copy_constructible<T>::value > = 0 >
bool f_impl() {
return true;
}
template< std::enable_if_t< !std::is_copy_constructible<T>::value > >
bool f_impl() {
return false;
}
};
int main() {
Derived<int> a;
std::cout<<a.f()<<"\n";
}
编译失败:
so.cpp: In instantiation of ‘class Derived<int>’:
so.cpp:29:18: required from here
so.cpp:18:10: error: ‘std::enable_if<true, void>::type’ {aka ‘void’} is not a valid type for a template non-type parameter
我显然在这里做错了什么,但我想不出正确的方法。
很遗憾,您不能这样做。 SFINAE 使用模板;例如以下代码根据您的第二个示例作品进行了修改。
template< typename X = T>
std::enable_if_t< std::is_copy_constructible<X>::value, bool >
f_impl() {
return true;
}
template< typename X = T>
std::enable_if_t< !std::is_copy_constructible<X>::value, bool >
f_impl() {
return false;
}
但是virtual
函数不能是模板,仅此而已。
使用 if constexpr
可以在编译时在函数内部分支,因此函数可以保持 virtual
:
bool f() override
{
if constexpr(std::is_copy_constructible<T>::value)
{
return true;
}
else
{
return false;
}
}
#include <type_traits>
class Base {
public:
virtual bool f() {
return true;
}
};
template<typename T>
class Derived : public Base {
std::enable_if_t< std::is_copy_constructible<T>::value, bool > f() override {
return true;
}
std::enable_if_t< !std::is_copy_constructible<T>::value, bool > f() override {
return false;
}
};
以上代码无法编译。出于某种原因我没能理解,编译器在 SFINAE 删除一个函数之前将这两个函数视为相同的重载。
但是,我不明白我将如何解决这个问题。我找到的文档 state 我应该在函数上使用模板。但是,这不起作用,因为该函数本来就是虚拟的。
我尝试通过调用非虚函数来解决问题,但我也无法编译它:
template<typename T>
class Derived : public Base {
virtual bool f() override {
return f_impl();
}
private:
template< std::enable_if_t< std::is_copy_constructible<T>::value > = 0 >
bool f_impl() {
return true;
}
template< std::enable_if_t< !std::is_copy_constructible<T>::value > >
bool f_impl() {
return false;
}
};
int main() {
Derived<int> a;
std::cout<<a.f()<<"\n";
}
编译失败:
so.cpp: In instantiation of ‘class Derived<int>’:
so.cpp:29:18: required from here
so.cpp:18:10: error: ‘std::enable_if<true, void>::type’ {aka ‘void’} is not a valid type for a template non-type parameter
我显然在这里做错了什么,但我想不出正确的方法。
很遗憾,您不能这样做。 SFINAE 使用模板;例如以下代码根据您的第二个示例作品进行了修改。
template< typename X = T>
std::enable_if_t< std::is_copy_constructible<X>::value, bool >
f_impl() {
return true;
}
template< typename X = T>
std::enable_if_t< !std::is_copy_constructible<X>::value, bool >
f_impl() {
return false;
}
但是virtual
函数不能是模板,仅此而已。
使用 if constexpr
可以在编译时在函数内部分支,因此函数可以保持 virtual
:
bool f() override
{
if constexpr(std::is_copy_constructible<T>::value)
{
return true;
}
else
{
return false;
}
}