c – 在显式实例化期间什么时候不完整类型没问题?
我正在尝试创建一种自动创建包装对象的包装类:
#include <memory> #include <type_traits> template<typename T> class Foo { std::unique_ptr<T> _x; public: Foo(); // will initialize _x }; 此外,我希望能够隐藏来自Foo< T>的用户的T的实现细节. (对于PIMPL pattern).对于单翻译单元示例,假设我有 struct Bar; // to be defined later extern template class Foo<Bar>; // or just imagine the code after main() is in a separate translation unit... int main() { Foo<Bar> f; // usable even though Bar is incomplete return 0; } // delayed definition of Bar and instantiation of Foo<Bar>: template<typename T> Foo<T>::Foo() : _x(std::make_unique<T>()) { } template class Foo<Bar>; struct Bar { // lengthy definition here... }; 一切正常.但是,如果我想要求T派生自另一个类,编译器会抱怨Bar不完整: struct Base {}; template<typename T> Foo<T>::Foo() : _x(std::make_unique<T>()) { // error: incomplete type 'Bar' used in type trait expression static_assert(std::is_base_of<Base,T>::value,"T must inherit from Base"); } 使用static_cast实现相同检查的尝试同样失败: template<typename T> Foo<T>::Foo() : _x(std::make_unique<T>()) { // error: static_cast from 'Bar *' to 'Base *',which are not related by inheritance,is not allowed // note: 'Bar' is incomplete (void)static_cast<Base*>((T*)nullptr); } 但是,似乎我添加了另一个级别的函数模板,我可以使这个工作: template<typename Base,typename T> void RequireIsBaSEOf() { static_assert(std::is_base_of<Base,"T must inherit from Base"); } // seems to work as expected template<typename T> Foo<T>::Foo() : _x((RequireIsBaSEOf<Base,T>(),std::make_unique<T>())) { } 请注意,即使以下类型仍然会导致不完整类型的错误,尽管结构相似: // error: incomplete type 'Bar' used in type trait expression template<typename T> Foo<T>::Foo() : _x((std::is_base_of<Base,std::make_unique<T>())) { } 这里发生了什么?附加函数是否以某种方式延迟了static_assert的检查?是否有一个更清洁的解决方案,不涉及添加功能,但仍然允许放置模板类Foo< Bar> ;;在定义Bar之前? 解决方法
版本1
// #1 // POI for Foo<Bar>: class templates with no dependent types are instantiated at correct scope BEFORE call,with no further lookup // after first parse int main() { Foo<Bar> f; // usable even though Bar is incomplete return 0; } // delayed definition of Bar and instantiation of Foo<Bar>: struct Base {}; // error: incomplete type 'Bar' used in type trait expression template<typename T> Foo<T>::Foo() : _x(std::make_unique<T>()) { // error: incomplete type 'Bar' used in type trait expression static_assert(std::is_base_of<Base,"T must inherit from Base"); } // #2 // POI for static_assert: function templates with no dependent types are // instantiated at correct scope AFTER call,but no further lookup is // performed,as with class templates without dependent types // is_base_of forces the compiler to generate a complete type here template class Foo<Bar>; struct Bar : private Base { // lengthy definition here... }; 版本2: struct Base {}; template<typename Base,std::make_unique<T>())) { } // #3 // is_base_of does not force any complete type,as so far,only the // incomplete type of RequiredIsBaSEOf is around. template class Foo<Bar>; struct Bar : private Base { // lengthy definition here... }; // #3 // POI for RequiredIsBaSEOf: function templates WITH dependent types are instantiated at correct scope AFTER call,after the second phase of two-phase lookup is performed. 以下是我认为的问题:
std::is_base_of需要一个完整的类型,因此当它不被RequiredIsBaSEOf隐藏时,可以将部分实例化的函数模板隐藏起来,is_base_of可以引导编译器尽快插入POI以发出错误. 正如t.niese所述,任何版本的godbolt上的gcc都可以采用-std = c 17标志.我的猜测是gcc做了最晚的POI之一,而clang使用了第一个合法的,#2.使用具有依赖名称的函数模板(当首次遇到RequiredIsBaSEOf时,仍然必须填写T)强制clang对依赖类型执行第二次查找运行,此时遇到了Bar. 我不确定如何实际验证这一点,所以来自更精通编译器的人的任何意见都会受到欢迎. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- c#连接sqlserver数据库、插入数据、从数据库获取时间示例
- ruby-on-rails – 每次控制器或模型更改时,Rails 5都会重新
- XML解析类NSXMLParser
- Unable to resolve module `react-native/Libraries/EventE
- 使用ROWNUM进行Oracle查询优化
- Cocos2d-x 3.0 回调函数
- ruby-on-rails-3 – Rails 3.1 ActiveAdmin GEM css / styl
- JAXBContext解析XML的常用注解
- c – OpenCV:处理每一帧
- 构建cocos2d-x android项目失败:未知的EABI对象属性44