我已经为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表达式与模板和非模板类一起使用?
发布评论