如何使SFINAE表达式与模板和非模板类一起使用?

编程入门 行业动态 更新时间:2024-10-26 19:25:09
本文介绍了如何使SFINAE表达式与模板和非模板类一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我已经为SFINAE做到了这一点:

I have made this for SFINAE:

// Type 'type' exists iff X is a base of COLLECTION template<typename X, typename COLLECTION, typename RET_TYPE = void> struct enable_if_is_base_of : std::enable_if<std::is_base_of<X, COLLECTION>::value, RET_TYPE> {};

对于以下情况,效果很好:

Which works well for something like this:

class A {}; class B {}; class C{}; class collection : A, B {}; template <typename X> typename enable_if_is_base_of<X, collection>::type fn(X&& x) { } int main() { fn(A()); fn(B()); // fn(C()); // Fails as expected return 0; }

但是,如果我要收集 可以从模板以及非模板类派生而来,我不确定该怎么做。

However, if I want collection to be derived from a template as well as non-template classes, I'm not sure how I would go about that.

类似这样的事情:

class A {}; template <typename X> class B {}; class C {}; template <typename X> class D {}; template <typename X> class collection : A, B<X> {}; // Stuff where the magic happens ... // Testing the magic template <typename X> // or other template declaration typename enable_if_is_base_of<X, collection>::type fn(X&& x) { } // May require more than one fn() declaration. int main() { fn(A()); fn(B<int>()); // fn(C()); // Fails to compile // fn(D<int>()); // Fails to compile return 0; }

如果收集类可以从任何类或具有任何类的类模板派生,则奖励点模板参数的数量。 :)

Bonus point if the collection class can derive from any class or class template with any number of template parameters. :)

推荐答案

经过反复尝试和测试,我想出了一个解决方案:

After much trying and testing I've come up with a solution:

#include<iostream> #include<type_traits> using namespace std; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Place Holder Class template <typename ...T> class PH {}; // Select a Collection to Test On // Since a collection is a template class that can derive from a non-template class // or template classes of an arbitrary number of typename parameters, these // functions selects one instance of the collection, for which the base can be // tested for. template < template <template <typename...> class, typename...> class C , template <typename...> class TT , typename...T> C<TT,T...> collection_selector(TT<T...>); template <template <template <typename...> class, typename...> class C, typename T> C<PH,T> collection_selector(T); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Aliases the type to make it more readable template <typename T, template <template <typename...> class, typename...> class C> is_base_of<T, decltype(collection_selector<C>(declval<T&>()))> enable_if_is_base_of_truth_selector(); // Not doing a direct 'using' to a type because of a bug in VC++ 2013. // See connect.microsoft/VisualStudio/feedback/details/1069557/failed-to-deduce-type-for-template-function template <typename T, template <template <typename...> class, typename...> class C> using is_base_of_truth = decltype(enable_if_is_base_of_truth_selector<T, C>()); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Aliases the type to make it more readable template <typename T, template <template <typename...> class, typename...> class C, typename RT> typename enable_if<is_base_of<T, decltype(collection_selector<C>(declval<T&>()))>::value, RT>::type enable_if_is_base_of_selector(); //typename enable_if<is_base_of_truth<T, C>::value, RT>::type enable_if_is_base_of_selector(); // Not doing a direct 'using' to a type because of a bug in VC++ 2013. // See connect.microsoft/VisualStudio/feedback/details/1069557/failed-to-deduce-type-for-template-function template <typename T, template <template <typename...> class, typename...> class C, typename RT = void> using enable_if_is_base_of = decltype(enable_if_is_base_of_selector<T, C, RT>()); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Select type from list template <unsigned int I, typename ...Ts> struct items; template <typename T, typename ...Ts> struct items<0, T, Ts...> { typedef T type; }; template <unsigned int I, typename T, typename ...Ts> struct items<I, T, Ts...> : items<I-1, Ts...> { }; template <unsigned int I> struct items<I> { typedef int type; }; template <unsigned int I, typename ...Ts> typename items<I, Ts...>::type get_item_selector(); template <unsigned int I, typename ...Ts> using get_item = decltype(get_item_selector<I, Ts...>()); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Classes to test on class A{}; template <typename T> class B{}; template <typename T0, typename T1> class BB{}; class C{}; template <typename T> class D{}; template <typename T0, typename T1> class DD{}; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Collection of valid types template < template <typename...> class TT , typename...Ts> class collection : A // class A , B<get_item<0,Ts...>> // class B<X> , BB<get_item<0,Ts...>, get_item<1,Ts...>> // class BB<Y, Z> {}; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to enable on template <typename T> enable_if_is_base_of<T, collection> test(T&&) { } int main() { cout << "-------------------------------------------------" << endl; cout << "Should all be 1." << endl; cout << is_base_of_truth<A , collection>::value << endl; cout << is_base_of_truth<B<char*> , collection>::value << endl; cout << is_base_of_truth<BB<int, float>, collection>::value << endl; cout << "-------------------------------------------------" << endl; cout << "Should all be 0." << endl; cout << is_base_of_truth<C , collection>::value << endl; cout << is_base_of_truth<D<char> , collection>::value << endl; cout << is_base_of_truth<DD<int, float&>, collection>::value << endl; cout << "-------------------------------------------------" << endl; // These succeed to compile since C, D<X> and DD<Y, Z> are the base of collection test(A()); test(B<int>()); test(BB<int, long>()); // These fail to compile since C, D<X> and DD<Y, Z> are NOT the base of collection //test(C()); // fails as expected //test(D<int>()); // fails as expected //test(DD<int, long>()); // fails as expected }

演示

注意:我必须更改的模板集合,以便它也包含模板。这使生活变得非常有趣,但确实使最终结果更具可读性,并提供了一些有趣的元函数。

NOTE: I had to change the template of the collection so that it included a template as well. This made life very interesting but it did make the final result more readable and made some interesting meta functions.

更多推荐

如何使SFINAE表达式与模板和非模板类一起使用?

本文发布于:2023-10-17 13:20:43,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1501044.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:模板   表达式   SFINAE

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!