c++ - Why variadic template constructor matches better than copy constructor? -


the following code not compile:

#include <iostream> #include <utility>  struct foo {     foo() { std::cout << "foo()" << std::endl; }     foo(int) { std::cout << "foo(int)" << std::endl; } };  template <typename t> struct bar {     foo foo;      bar(const bar&) { std::cout << "bar(const bar&)" << std::endl; }      template <typename... args>     bar(args&&... args) : foo(std::forward<args>(args)...)     {         std::cout << "bar(args&&... args)" << std::endl;     } };  int main() {     bar<foo> bar1{};     bar<foo> bar2{bar1}; } 

compiler error suggest me compiler trying use variadic template constructor instead of copy constructor:

prog.cpp: in instantiation of 'bar<t>::bar(args&& ...) [with args = {bar<foo>&}; t = foo]': prog.cpp:27:20:   required here prog.cpp:18:55: error: no matching function call 'foo::foo(bar<foo>&)'   bar(args&&... args) : foo(std::forward<args>(args)...) 

why compiler , how fix it?

this call:

bar<foo> bar2{bar1}; 

has 2 candidates in overload set:

bar(const bar&); bar(bar&);       // args... = {bar&} 

one of ways determine if 1 conversion sequence better other is, [over.ics.rank]:

standard conversion sequence s1 better conversion sequence standard conversion sequence s2 if

— [...]
— s1 , s2 reference bindings (8.5.3), , types references refer same type except top-level cv-qualifiers, , type reference initialized s2 refers more cv-qualified type reference initialized s1 refers. [ example:

int f(const int &); int f(int &); int g(const int &); int g(int);  int i; int j = f(i);    // calls f(int &) int k = g(i);    // ambiguous 

—end example ]

the forwarding reference variadic constructor better match because reference binding (bar&) less cv-qualified copy constructor's reference binding (const bar&).

as far solutions, exclude candidate set anytime args... should call copy or move constructor sfinae:

template <typename... > struct typelist;  template <typename... args,           typename = std::enable_if_t<               !std::is_same<typelist<bar>,                             typelist<std::decay_t<args>...>>::value           >> bar(args&&... args) 

if args... 1 of bar, bar&, bar&&, const bar&, typelist<decay_t<args>...> typelist<bar> - , that's case want exclude. other set of args... allowed fine.


Comments

Popular posts from this blog

c# - Better 64-bit byte array hash -

webrtc - Which ICE candidate am I using and why? -

php - Zend Framework / Skeleton-Application / Composer install issue -