![]() |
strange compile problem regarding const-ref v.s. perfect forwarding
Can anyone please tell me what I'm doing wrong in the stripped-down code below?
I can't figure out the cause of failure when compiling, tried both clang++4.1 and g++4.8 with -std=c++11. Thanks very much!! ---------------------------------------------------- #include <utility> namespace test { template < typename D > struct base{}; struct MyP : base<MyP> { explicit MyP(int){} }; template < typename T > struct remove_cvr { typedef typename std::remove_cv< typename std::remove_reference<T>::type >::type type; }; template < typename... P > struct array_impl; // single element, recursive root template < typename P > struct array_impl<P> { P head_; template < typename Q > explicit array_impl(Q&& q):head_(q){} // fail to compile, why? }; template < typename P, typename... T > struct array_impl<P,T...> { P head_; array_impl<T...> tail_; template < typename Q, typename... U > explicit array_impl(Q&& q, U&&... u):head_(std::forward<Q>(q)),tail_(std::forward<U> (u)...) {} }; template < typename... P > struct array : public array_impl<P...>, public base<array<P...>> { typedef array_impl<P...> impl_base; template < typename... Q > explicit array(Q&&... q):impl_base(std::forward<Q>(q)...){} }; template < typename... P > array<typename remove_cvr<P>::type...> make_array(P&&... p) { return array<typename remove_cvr<P>::type...>(std::forward<P>(p)...); } //// compiles fine if not trying to forward //template < typename... P > //array<typename remove_cvr<P>::type...> make_array(const P&... p) //{ // return array<typename remove_cvr<P>::type...>(p...); //} } int main(int argc, const char * argv[]) { using namespace test; // make_array(MyP(3.4)); // compiles fine make_array(make_array(MyP(3.4))); // failed both g++4.8 and clang++4.1 (mac osx 10.8.2) return 0; } |
Re: strange compile problem regarding const-ref v.s. perfect forwarding
On Monday, October 29, 2012 9:59:13 AM UTC-7, hui...@gmail.com wrote:
> Can anyone please tell me what I'm doing wrong in the stripped-down code below? I can't figure out the cause of failure when compiling, tried both clang++4.1 and g++4.8 with -std=c++11. Thanks very much!! ---------------------------------------------------- #include <utility> namespace test { template < typename D > struct base{}; struct MyP : base<MyP> { explicit MyP(int){} }; template < typename T > struct remove_cvr { typedef typename std::remove_cv< typename std::remove_reference<T>::type >::type type; }; template < typename... P > struct array_impl; // single element, recursive root template < typename P > struct array_impl<P> { P head_; template < typename Q > explicit array_impl(Q&& q):head_(q){} // fail to compile, why? }; template < typename P, typename... T > struct array_impl<P,T...> { P head_; array_impl<T...> tail_; template < typename Q, typename... U > explicit array_impl(Q&& q, U&&... u):head_(std::forward<Q>(q)),tail_(std::forward<U> (u)...){} }; template < typename... P > struct array : public array_impl<P...>, public base<array<P...>> { typedef array_impl<P...> impl_base; template < typename... Q > explicit array(Q&&... q):impl_base(std::forward<Q>(q)...){} }; template < typename... P > array<typename remove_cvr<P>::type...> make_array(P&&... p) { return array<typename remove_cvr<P>::type...>(std::forward<P>(p)...); } //// compiles fine if not trying to forward //template < typename... P > //array<typename remove_cvr<P>::type...> make_array(const P&... p) //{ // return array<typename remove_cvr<P>::type...>(p...); //} } int main(int argc, const char * argv[]) { using namespace test; // make_array(MyP(3.4)); // compiles fine make_array(make_array(MyP(3.4))); // failed both g++4.8 and clang++4.1 (mac osx 10.8.2) return 0; } It would help if you told us what the error message was, and where it occurred. |
Re: strange compile problem regarding const-ref v.s. perfect forwarding
Sure, here are the full output from compiling, for both g++ and clang++.
With g++ 4.8: -------------------- main.cpp: In instantiation of 'test::array_impl<P>::array_impl(Q&&) [with Q = test::array<test::MyP>&; P = test::MyP]': main.cpp:36:88: required from 'test::array<P>::array(Q&& ...) [with Q = {test::array<test::MyP>&}; P = {test::MyP}]' main.cpp:22:63: required from 'test::array_impl<P>::array_impl(Q&&) [with Q = test::array<test::MyP>; P = test::array<test::MyP>]' main.cpp:36:88: required from 'test::array<P>::array(Q&& ...) [with Q = {test::array<test::MyP>}; P = {test::array<test::MyP>}]' main.cpp:42:72: required from 'test::array<typename test::remove_cvr<P>::type ...> test::make_array(P&& ...) [with P = {test::array<test::MyP>}; typename test::remove_cvr<P>::type = <type error>]' main.cpp:59:36: required from here main.cpp:22:63: error: no matching function for call to 'test::MyP::MyP(test::array<test::MyP>&)' template < typename Q > explicit array_impl(Q&& q):head_(q){} // fail to compile, why? ^ main.cpp:22:63: note: candidates are: main.cpp:6:35: note: test::MyP::MyP(int) struct MyP : base<MyP> { explicit MyP(int){} }; ^ main.cpp:6:35: note: no known conversion for argument 1 from 'test::array<test::MyP>' to 'int' main.cpp:6:8: note: constexpr test::MyP::MyP(const test::MyP&) struct MyP : base<MyP> { explicit MyP(int){} }; ^ main.cpp:6:8: note: no known conversion for argument 1 from 'test::array<test::MyP>' to 'const test::MyP&' main.cpp:6:8: note: constexpr test::MyP::MyP(test::MyP&&) main.cpp:6:8: note: no known conversion for argument 1 from 'test::array<test::MyP>' to 'test::MyP&&' mbpro:test huil$ ------------------ From clang++4.1: ------------------ main.cpp:22:56: error: no matching constructor for initialization of 'test::MyP' template < typename Q > explicit array_impl(Q&& q):head_(q){} // fail to compile, why? ^ ~ main.cpp:36:57: note: in instantiation of function template specialization 'test::array_impl<test::MyP>::array_impl<test::arr ay<test::MyP> &>' requested here template < typename... Q > explicit array(Q&&... q):impl_base(std::forward<Q>(q)...){} ^ main.cpp:22:56: note: in instantiation of function template specialization 'test::array<test::MyP>::array<test::array<test::M yP> &>' requested here template < typename Q > explicit array_impl(Q&& q):head_(q){} // fail to compile, why? ^ main.cpp:36:57: note: in instantiation of function template specialization 'test::array_impl<test::array<test::MyP> >::array_impl<test::array<test::MyP> >' requested here template < typename... Q > explicit array(Q&&... q):impl_base(std::forward<Q>(q)...){} ^ main.cpp:42:12: note: in instantiation of function template specialization 'test::array<test::array<test::MyP> >::array<test::array<test::MyP> >' requested here return array<typename remove_cvr<P>::type...>(std::forward<P>(p)...); ^ main.cpp:59:5: note: in instantiation of function template specialization 'test::make_array<test::array<test::MyP> >' requested here make_array(make_array(MyP(3.4))); // failed both g++4.8 and clang++4.1 (mac osx 10.8.2) ^ main.cpp:6:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'test::array<test::MyP>' to 'const test::MyP' for 1st argument; struct MyP : base<MyP> { explicit MyP(int){} }; ^ main.cpp:6:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'test::array<test::MyP>' to 'test::MyP' for 1st argument; struct MyP : base<MyP> { explicit MyP(int){} }; ^ main.cpp:6:35: note: candidate constructor not viable: no known conversion from 'test::array<test::MyP>' to 'int' for 1st argument; struct MyP : base<MyP> { explicit MyP(int){} }; ^ 1 error generated. ------------------------ |
Re: strange compile problem regarding const-ref v.s. perfect forwarding
Thanks for replying. The reason to use to template constructor is to be able to perfectly forward arguments. Your solution doesn't allow array_impl to be constructed from lvalues, does it?
I just figured out a way to fix my code. I need to selectively enable the template constructors only when types are compatible (in my case, exactly the same up to cv qualifier and reference, lvalue or rvalue), hence this: template < typename P > struct array_impl<P> { P head_; template < typename Q, class = typename std::enable_if<std::is_same<P,typename remove_cvr<Q>::type>::value>::type > explicit array_impl(Q&& q):head_(q){} }; And of course the equivalent for the variadic one (slightly more complicated, so omitted here). Everything works now. |
| All times are GMT. The time now is 11:09 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.