- SFINAE question - 6 Updates
- Project symbiosis - 4 Updates
- vector<>::erase-behaviour - 4 Updates
- c++ is a cobol, c still being great - 1 Update
- neos the universal compiler - progress - 1 Update
Daniel <danielaparker@gmail.com>: Apr 06 05:00PM -0700 Consider the function template <class J> J f() { return J(); } I'd like to have two implementations of f. One when J is an instantiation of the template class template <class T> struct A { typedef T t_type; typedef typename T::char_type char_type; // (*) }; And a second when J is any other class that has a default constructor. I tried the following: template <class T,class Enable=void> struct is_A : std::false_type {}; template <class T> struct is_A<T, decltype(std::declval<A<typename T::t_type>>(),void())> : std::true_type {}; template <class J> typename std::enable_if<is_A<J>::value,J>::type f() { std::cout << "J is a specialization of A\n"; return J(); } template <class J> typename std::enable_if<!is_A<J>::value, J>::type f() { std::cout << "J is not a specialization of A\n"; return J(); } But when attempting to construct struct B { typedef char char_type; }; auto j1 = f<A<B>>(); // (1) auto j2 = f<std::vector<int>>(); // (2) (2) fails to compile because of line (*) in the definition of A. So this approach doesn't work. Any suggestions? Thanks, Daniel |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 07 05:44AM +0200 On 07.04.2019 02:00, Daniel wrote: > Any suggestions? > Thanks, > Daniel Your code, with necessary #include statements added as shown below, works with MingW g++ 8.2.0 and Visual C++ 2019, Try to create a small but complete example that reproduces the undesired behavior. When/if you ask here about it, if it still doesn't work, consider ALL the points in the FAQ item "How do I post a question about code that doesn't work correctly?", available at e.g. <url: http://www.dietmar-kuehl.de/mirror/c++-faq/how-to-post.html#faq-5.8>. ------------------------------------------------------------------------- #include <type_traits> // std::false_type // template <class J> // J f() // { // return J(); // } template <class T> struct A { typedef T t_type; typedef typename T::char_type char_type; // (*) }; template <class T,class Enable=void> struct is_A : std::false_type {}; template <class T> struct is_A<T, decltype(std::declval<A<typename T::t_type>>(),void())> : std::true_type {}; #include <iostream> #include <vector> template <class J> typename std::enable_if<is_A<J>::value,J>::type f() { std::cout << "J is a specialization of A\n"; return J(); } template <class J> typename std::enable_if<!is_A<J>::value, J>::type f() { std::cout << "J is not a specialization of A\n"; return J(); } struct B { typedef char char_type; }; auto main() -> int { auto j1 = f<A<B>>(); // (1) auto j2 = f<std::vector<int>>(); // (2) (void)j1, (void)j2; } ------------------------------------------------------------------------- Results: J is a specialization of A J is not a specialization of A The code can IMO be expressed more cleanly, but that's a different matter. Cheers!, - Alf |
Sam <sam@email-scan.com>: Apr 07 08:41AM -0400 Daniel writes: > typedef typename T::char_type char_type; // (*) > }; > And a second when J is any other class that has a default constructor. It's much simpler to avoid SFINAE with an inline wrapper that uses partial specialization of a template type. I expect any modern C++ compiler to optimize away the wrapper call to nothing. #include <iostream> template <class T> struct A { typedef T t_type; }; template <class J> struct generic_f { static J f() { std::cout << "Generic" << std::endl; return J(); } }; template<typename J> struct generic_f<A<J>> { static A<J> f() { std::cout << "Specialized" << std::endl; return A<J>(); } }; template <class T> inline T f() { return generic_f<T>::f(); } int main() { f<int>(); f<A<int>>(); return 0; } |
Daniel <danielaparker@gmail.com>: Apr 07 07:48AM -0700 On Saturday, April 6, 2019 at 11:44:34 PM UTC-4, Alf P. Steinbach wrote: > Your code, with necessary #include statements added as shown below, > works with MingW g++ 8.2.0 and Visual C++ 2019, But not with Visual C++ 140 (2015) or 141 (vs 2017). Given that, I had assumed something was wrong with my understanding of SFINAE with decltype and declval, but I checked and I see that it does work with GCC 4.8 and later on linux, and clang 3.9 and later on linux, so I guess this is an earlier Visual C++ bug. But nonetheless, a showstopper, the code having to work in all these environments. I don't suppose you would have any suggested alternatives that would work with Visual C++ 140 (2015) or 141 (vs 2017)? Thanks, Daniel |
Daniel <danielaparker@gmail.com>: Apr 07 07:54AM -0700 On Sunday, April 7, 2019 at 8:41:50 AM UTC-4, Sam wrote: > It's much simpler to avoid SFINAE with an inline wrapper that uses partial > specialization of a template type. I expect any modern C++ compiler to > optimize away the wrapper call to nothing. Thanks, I may end up doing it that way. Daniel |
Daniel <danielaparker@gmail.com>: Apr 07 12:33PM -0700 On Sunday, April 7, 2019 at 10:49:00 AM UTC-4, Daniel wrote: > > Your code, with necessary #include statements added as shown below, > > works with MingW g++ 8.2.0 and Visual C++ 2019, > But not with Visual C++ 140 (2015) or 141 (vs 2017). I'm currently experimenting with code similar to that below. Any additional comments appreciated. Thanks, Daniel #include <type_traits> #include <iostream> #include <vector> template <class T> struct A { typedef T t_type; typedef typename T::char_type char_type; // (*) }; template <class T,class Enable=void> struct is_A : std::false_type {}; #if defined(_MSC_VER) && _MSC_VER < 1916 template <class T> struct is_A<T, typename std::enable_if<!std::is_void<typename T::t_type>::value && !std::is_void<typename T::char_type>::value>::type> : std::true_type {}; #else template <class T> struct is_A<T, decltype(std::declval<A<typename T::t_type>>(),void())> : std::true_type {};
Subscribe to:
Post Comments (Atom)
|
No comments:
Post a Comment