Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > strange compile problem regarding const-ref v.s. perfect forwarding

Reply
Thread Tools

strange compile problem regarding const-ref v.s. perfect forwarding

 
 
huili80@gmail.com
Guest
Posts: n/a
 
      10-29-2012
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;
}

 
Reply With Quote
 
 
 
 
FredK
Guest
Posts: n/a
 
      10-29-2012
On Monday, October 29, 2012 9:59:13 AM UTC-7, (E-Mail Removed) 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.
 
Reply With Quote
 
 
 
 
huili80@gmail.com
Guest
Posts: n/a
 
      10-29-2012
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.
------------------------

 
Reply With Quote
 
huili80@gmail.com
Guest
Posts: n/a
 
      10-29-2012
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.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Perfect Forwarding in Runtime (rvalue reference) dervih C++ 3 07-13-2012 02:03 PM
using std::function, std::bind, perfect forwarding Andrew Tomazos C++ 1 12-23-2011 10:19 AM
Specializing Perfect Forwarding Templates? Scott Meyers C++ 20 03-16-2011 07:07 PM
Perfect Forwarding + static_assert [C++0x] Scott Meyers C++ 6 12-05-2010 08:21 PM
Perfect function forwarding Alexis Nikichine Javascript 6 12-28-2005 02:39 PM



Advertisments