Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   strange compile problem regarding const-ref v.s. perfect forwarding (http://www.velocityreviews.com/forums/t954018-strange-compile-problem-regarding-const-ref-v-s-perfect-forwarding.html)

huili80@gmail.com 10-29-2012 04:59 PM

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;
}


FredK 10-29-2012 06:08 PM

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.

huili80@gmail.com 10-29-2012 07:56 PM

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.
------------------------


huili80@gmail.com 10-29-2012 09:11 PM

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 12:37 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.