C++14中结合复杂谓词使用std::enable_if的编译问题解决
问题:C++14下自定义or_模板实现类型约束编译失败
工作环境仅支持C14,需用std::enable_if为函数添加类型约束,因无法使用C17的std::disjunction,从libc的type_traits头文件引入or_模板并封装为IsVectorOrList结构体。但将函数返回类型约束改为typename std::enable_if<IsVectorOrList<T>::value, void>::type时编译报错,直接使用typename std::enable_if<IsVector<T>::value || IsList<T>::value, void>::type则正常编译。
原代码
#include <type_traits> #include <iostream> #include <vector> #include <list> template <typename T> struct IsVector : public std::false_type {}; template <typename T> struct IsVector<std::vector<T>> : public std::true_type {}; template <typename T> struct IsList : public std::false_type {}; template <typename T> struct IsList<std::list<T>> : public std::true_type {}; // taken from libc type_traits template <bool, typename, typename> struct conditional; template <typename...> struct or_; template <> struct or_<> : public std::false_type {}; template <typename _B1> struct or_<_B1> : public _B1 {}; template <typename _B1, typename _B2> struct or_<_B1, _B2> : public conditional<_B1::value, _B1, _B2>::type {}; template <typename _B1, typename _B2, typename _B3, typename... _Bn> struct or_<_B1, _B2, _B3, _Bn...> : public conditional<_B1::value, _B1, or_<_B2, _B3, _Bn...>>::type {}; // --- template <typename T> struct IsVectorOrList : public or_<IsVector<T>, IsList<T>>::type {}; template <typename T> typename std::enable_if<IsVector<T>::value || IsList<T>::value, void>::type // replacing with this line does not work //typename std::enable_if<IsVectorOrList<T>::value, void>::type foo(const T& list) { for (const auto& item : list) { std::cout << item << std::endl; } } int main() { foo(std::vector<int>{17, 42}); foo(std::list<float>{1.0, 2.71, 3.14}); }
编译错误信息
traits.cpp:32:8: error: invalid use of incomplete type ‘struct conditional<true, IsVector<std::vector<int> >, IsList<std::vector<int> > >’ 32 | struct or_<_B1, _B2> : public conditional<_B1::value, _B1, _B2>::type {}; | ^~~~~~~~~~~~~ traits.cpp:20:8: note: declaration of ‘struct conditional<true, IsVector<std::vector<int> >, IsList<std::vector<int> > >’ 20 | struct conditional; | ^~~~~~~~~~~
错误原因
你只对conditional结构体做了前向声明,没有提供完整的定义。C++11及以后标准库已经提供了std::conditional,但你自定义的conditional未实现,导致编译器无法实例化该模板,从而报错。
修改方案
方案1:使用标准库的std::conditional
直接删除自定义的conditional前向声明,将or_模板中的conditional替换为std::conditional即可,C++14完全支持std::conditional:
#include <type_traits> #include <iostream> #include <vector> #include <list> template <typename T> struct IsVector : public std::false_type {}; template <typename T> struct IsVector<std::vector<T>> : public std::true_type {}; template <typename T> struct IsList : public std::false_type {}; template <typename T> struct IsList<std::list<T>> : public std::true_type {}; // 修改or_模板,使用std::conditional template <typename...> struct or_; template <> struct or_<> : public std::false_type {}; template <typename _B1> struct or_<_B1> : public _B1 {}; template <typename _B1, typename _B2> struct or_<_B1, _B2> : public std::conditional<_B1::value, _B1, _B2>::type {}; template <typename _B1, typename _B2, typename _B3, typename... _Bn> struct or_<_B1, _B2, _B3, _Bn...> : public std::conditional<_B1::value, _B1, or_<_B2, _B3, _Bn...>>::type {}; // --- template <typename T> struct IsVectorOrList : public or_<IsVector<T>, IsList<T>>::type {}; template <typename T> // 现在可以正常使用IsVectorOrList了 typename std::enable_if<IsVectorOrList<T>::value, void>::type foo(const T& list) { for (const auto& item : list) { std::cout << item << std::endl; } } int main() { foo(std::vector<int>{17, 42}); foo(std::list<float>{1.0, 2.71, 3.14}); }
方案2:补全自定义conditional的实现
如果一定要自己实现conditional,添加完整定义:
template <bool B, typename T, typename F> struct conditional { typedef T type; }; template <typename T, typename F> struct conditional<false, T, F> { typedef F type; };
将这段代码放在or_模板之前即可。
说明
两种方案都能解决问题,优先推荐方案1,直接复用标准库组件更可靠,避免重复造轮子。
内容的提问来源于stack exchange,提问作者bselu
相关产品推荐
相关产品推荐

