【发布时间】:2021-08-29 01:27:35
【问题描述】:
我正在尝试实现转换函数运算符,并使用 std::is_base_of 来限制适用范围,但我遇到了问题。
#include <type_traits>
class Spurious;
class MyClassBase {};
template< typename T >
class MyClass: public MyClassBase {
public:
template< typename U, std::enable_if_t< std::is_base_of<MyClassBase, U>::value, bool> = true >
operator U () const {
return U{}; // Complex initialization omitted for brevity
}
};
class MyBool: public MyClass< bool > {};
class MyInt: public MyClass< int > {};
int do_stuff( int i, Spurious const & obj);
int do_stuff( int i, MyBool const & obj) {
return i;
}
int main() {
MyInt const obj;
return do_stuff( 3, obj );
}
存在 Spurious 和相关函数定义意味着我在 is_base_of 实现中遇到编译器错误(compiler explorer;GCC:error: invalid use of incomplete type 'const class Spurious'Clang:error: incomplete type 'Spurious' used in type trait expression)。
我明白为什么你不能 is_base_of 一个不完整的类型,但我不太明白为什么“替换失败不是错误”在这里不适用。我原以为在模板扩展期间尝试 is_base_of 不完整类型会导致编译器中止转换尝试并继续下一个函数定义。这就是这里 is_base_of 语句的全部要点:忽略与模式不匹配的类。
不过,我的主要问题不是“为什么”,而是“下一步是什么”。有什么解决方法吗?是否有某种方法可以忽略诸如 Spurious 之类的东西,而不需要在此编译单元中完全定义它们?理想情况下,我只需修改转换运算符的定义(例如 SFINAE 模板参数)即可使其工作。
【问题讨论】:
-
SFINAE 不适用于不完整的类型,因为您不希望像
is_base_of这样的静态评估表达式 根据外部可能发生的变化返回不同的值。例如,两个不同的来源可能包含此代码作为标头——包含的顺序可能提供Spurious的定义。然后突然你的评估顺序可能会改变。如果Spurious继承自MyClassBase怎么办?有定义的来源突然会出现歧义错误,但不完整的来源不会。
标签: c++ c++17 sfinae typetraits conversion-operator