Bug 69853 - An inheriting constructor of the class that inherited std::tuple isn't called correctly
Summary: An inheriting constructor of the class that inherited std::tuple isn't called...
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: ---
Assignee: Ville Voutilainen
URL:
Keywords:
: 81527 (view as bug list)
Depends on:
Blocks:
 
Reported: 2016-02-17 12:58 UTC by Takatoshi Kondo
Modified: 2017-07-25 21:07 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-02-17 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Takatoshi Kondo 2016-02-17 12:58:46 UTC
Code

#include <tuple>

template <typename... Types>
struct my_tuple : std::tuple<Types...> {
    // inheriting constructor
    using std::tuple<Types...>::tuple;
};

int main() {
    std::tuple<int> st;
    my_tuple<int> mt(st);
}


Compiler version

$ /home/kondo/local/usr/local/bin/g++ -v
Using built-in specs.
COLLECT_GCC=/home/kondo/local/usr/local/bin/g++
COLLECT_LTO_WRAPPER=/home/kondo/local/usr/local/bin/../libexec/gcc/x86_64-pc-linux-gnu/6.0.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../gcc/configure --disable-multilib --enable-languages=c,c++
Thread model: posix
gcc version 6.0.0 20160217 (experimental) (GCC) 


Git (git://gcc.gnu.org/git/gcc.git) hash
commit 0d85ea34a029adf4c3c31edaf8a317905d852faa


Environment 

$ uname -a
Linux archboltz 4.3.3-2-ARCH #1 SMP PREEMPT Wed Dec 23 20:09:18 CET 2015 x86_64 GNU/Linux


Error log

$ /home/kondo/local/usr/local/bin/g++ -std=c++11 test.cpp

test.cpp: In function ‘int main()’:
test.cpp:11:24: error: no matching function for call to ‘my_tuple<int>::my_tuple(std::tuple<int>&)’
     my_tuple<int> mt(st);
                        ^
test.cpp:4:8: note: candidate: constexpr my_tuple<int>::my_tuple()
 struct my_tuple : std::tuple<Types...> {
        ^~~~~~~~
test.cpp:4:8: note:   candidate expects 0 arguments, 1 provided
test.cpp:6:33: note: candidate: template<class _Dummy, typename std::enable_if<((std::_TC<std::is_same<_Dummy, void>::value, int>::_ConstructibleTuple<int>() && std::_TC<std::is_same<_Dummy, void>::value, int>::_ImplicitlyConvertibleTuple<int>()) && (1ul >= 1)), bool>::type <anonymous> > constexpr my_tuple<int>::my_tuple(const int&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   cannot convert ‘st’ (type ‘std::tuple<int>’) to type ‘const int&’
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Dummy, typename std::enable_if<((std::_TC<std::is_same<_Dummy, void>::value, int>::_ConstructibleTuple<int>() && (! std::_TC<std::is_same<_Dummy, void>::value, int>::_ImplicitlyConvertibleTuple<int>())) && (1ul >= 1)), bool>::type <anonymous> > constexpr my_tuple<int>::my_tuple(const int&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   cannot convert ‘st’ (type ‘std::tuple<int>’) to type ‘const int&’
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class ... _UElements, typename std::enable_if<((std::_TC<(1ul == sizeof... (_UElements)), int>::_MoveConstructibleTuple<_UElements ...>() && std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyMoveConvertibleTuple<_UElements ...>()) && (1ul >= 1)), bool>::type <anonymous> > constexpr my_tuple<int>::my_tuple(_UElements&& ...)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
In file included from test.cpp:1:0:
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:619:21: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
         bool>::type=true>
                     ^~~~
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:619:21: note: invalid template non-type parameter
test.cpp:6:33: note: candidate: template<class ... _UElements, typename std::enable_if<((std::_TC<(1ul == sizeof... (_UElements)), int>::_MoveConstructibleTuple<_UElements ...>() && (! std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyMoveConvertibleTuple<_UElements ...>())) && (1ul >= 1)), bool>::type <anonymous> > constexpr my_tuple<int>::my_tuple(_UElements&& ...)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
In file included from test.cpp:1:0:
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:629:21: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
         bool>::type=false>
                     ^~~~~
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:629:21: note: invalid template non-type parameter
test.cpp:6:33: note: candidate: template<class ... _UElements, class _Dummy, typename std::enable_if<((std::_TC<(1ul == sizeof... (_UElements)), int>::_ConstructibleTuple<_UElements ...>() && std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyConvertibleTuple<_UElements ...>()) && std::_TC<(std::is_same<_Dummy, void>::value && (1ul == 1)), int>::_NonNestedTuple<const tuple<_Elements ...>&>()), bool>::type <anonymous> > constexpr my_tuple<int>::my_tuple(const std::tuple<_Elements ...>&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
In file included from test.cpp:1:0:
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:650:21: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
         bool>::type=true>
                     ^~~~
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:650:21: note: invalid template non-type parameter
test.cpp:6:33: note: candidate: template<class ... _UElements, class _Dummy, typename std::enable_if<((std::_TC<(1ul == sizeof... (_UElements)), int>::_ConstructibleTuple<_UElements ...>() && (! std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyConvertibleTuple<_UElements ...>())) && std::_TC<(std::is_same<_Dummy, void>::value && (1ul == 1)), int>::_NonNestedTuple<const tuple<_Elements ...>&>()), bool>::type <anonymous> > constexpr my_tuple<int>::my_tuple(const std::tuple<_Elements ...>&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
In file included from test.cpp:1:0:
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:662:21: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
         bool>::type=false>
                     ^~~~~
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:662:21: note: invalid template non-type parameter
test.cpp:6:33: note: candidate: template<class ... _UElements, class _Dummy, typename std::enable_if<((std::_TC<(1ul == sizeof... (_UElements)), int>::_MoveConstructibleTuple<_UElements ...>() && std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyMoveConvertibleTuple<_UElements ...>()) && std::_TC<(std::is_same<_Dummy, void>::value && (1ul == 1)), int>::_NonNestedTuple<tuple<_Elements ...>&&>()), bool>::type <anonymous> > constexpr my_tuple<int>::my_tuple(std::tuple<_Elements ...>&&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
In file included from test.cpp:1:0:
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:674:21: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
         bool>::type=true>
                     ^~~~
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:674:21: note: invalid template non-type parameter
test.cpp:6:33: note: candidate: template<class ... _UElements, class _Dummy, typename std::enable_if<((std::_TC<(1ul == sizeof... (_UElements)), int>::_MoveConstructibleTuple<_UElements ...>() && (! std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyMoveConvertibleTuple<_UElements ...>())) && std::_TC<(std::is_same<_Dummy, void>::value && (1ul == 1)), int>::_NonNestedTuple<tuple<_Elements ...>&&>()), bool>::type <anonymous> > constexpr my_tuple<int>::my_tuple(std::tuple<_Elements ...>&&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
In file included from test.cpp:1:0:
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:685:21: error: no type named ‘type’ in ‘struct std::enable_if<false, bool>’
         bool>::type=false>
                     ^~~~~
/home/kondo/local/usr/local/include/c++/6.0.0/tuple:685:21: note: invalid template non-type parameter
test.cpp:6:33: note: candidate: template<class _Alloc> my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects 2 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Alloc, class _Dummy, typename std::enable_if<(std::_TC<std::is_same<_Dummy, void>::value, int>::_ConstructibleTuple<int>() && std::_TC<std::is_same<_Dummy, void>::value, int>::_ImplicitlyConvertibleTuple<int>()), bool>::type <anonymous> > my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&, const int&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects 3 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Alloc, class _Dummy, typename std::enable_if<(std::_TC<std::is_same<_Dummy, void>::value, int>::_ConstructibleTuple<int>() && (! std::_TC<std::is_same<_Dummy, void>::value, int>::_ImplicitlyConvertibleTuple<int>())), bool>::type <anonymous> > my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&, const int&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects 3 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Alloc, class ... _UElements, typename std::enable_if<(std::_TC<(1ul == sizeof... (_UElements)), int>::_MoveConstructibleTuple<_UElements ...>() && std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyMoveConvertibleTuple<_UElements ...>()), bool>::type <anonymous> > my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&, _UElements&& ...)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects at least 2 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Alloc, class ... _UElements, typename std::enable_if<(std::_TC<(1ul == sizeof... (_UElements)), int>::_MoveConstructibleTuple<_UElements ...>() && (! std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyMoveConvertibleTuple<_UElements ...>())), bool>::type <anonymous> > my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&, _UElements&& ...)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects at least 2 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Alloc> my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&, const std::tuple<int>&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects 3 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Alloc> my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&, std::tuple<int>&&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects 3 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Alloc, class ... _UElements, typename std::enable_if<(std::_TC<(1ul == sizeof... (_UElements)), int>::_ConstructibleTuple<_UElements ...>() && std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyConvertibleTuple<_UElements ...>()), bool>::type <anonymous> > my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&, const std::tuple<_Elements ...>&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects 3 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Alloc, class ... _UElements, typename std::enable_if<(std::_TC<(1ul == sizeof... (_UElements)), int>::_ConstructibleTuple<_UElements ...>() && (! std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyConvertibleTuple<_UElements ...>())), bool>::type <anonymous> > my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&, const std::tuple<_Elements ...>&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects 3 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Alloc, class ... _UElements, typename std::enable_if<(std::_TC<(1ul == sizeof... (_UElements)), int>::_MoveConstructibleTuple<_UElements ...>() && std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyMoveConvertibleTuple<_UElements ...>()), bool>::type <anonymous> > my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&, std::tuple<_Elements ...>&&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects 3 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:6:33: note: candidate: template<class _Alloc, class ... _UElements, typename std::enable_if<(std::_TC<(1ul == sizeof... (_UElements)), int>::_MoveConstructibleTuple<_UElements ...>() && (! std::_TC<(1ul == sizeof... (_UElements)), int>::_ImplicitlyMoveConvertibleTuple<_UElements ...>())), bool>::type <anonymous> > my_tuple<int>::my_tuple(std::allocator_arg_t, const _Alloc&, std::tuple<_Elements ...>&&)
     using std::tuple<Types...>::tuple;
                                 ^~~~~
test.cpp:6:33: note:   template argument deduction/substitution failed:
test.cpp:11:24: note:   candidate expects 3 arguments, 1 provided
     my_tuple<int> mt(st);
                        ^
test.cpp:4:8: note: candidate: constexpr my_tuple<int>::my_tuple(const my_tuple<int>&)
 struct my_tuple : std::tuple<Types...> {
        ^~~~~~~~
test.cpp:4:8: note:   no known conversion for argument 1 from ‘std::tuple<int>’ to ‘const my_tuple<int>&’
test.cpp:4:8: note: candidate: constexpr my_tuple<int>::my_tuple(my_tuple<int>&&)
test.cpp:4:8: note:   no known conversion for argument 1 from ‘std::tuple<int>’ to ‘my_tuple<int>&&’


Note

It works on g++ 5.3.0 and clang++ 3.7.1.
Comment 1 Ville Voutilainen 2016-02-17 13:50:17 UTC
I'll see what I can do.
Comment 2 Ville Voutilainen 2016-02-17 18:15:03 UTC
The fix for http://cplusplus.github.io/LWG/lwg-active.html#2549 breaks
this code. But that breakage looks sane, because it prevents implicit
base-to-derived conversions that create temporaries. Consider the following code,
which is valid on 5.x but ill-formed on 6:

#include <tuple>
#include <iostream>

using std::tuple;

template <class... Args> struct mytuple : tuple<Args...> 
{
    using tuple<Args...>::tuple;
}; 

void f(const mytuple<int, int>& ft) 
{
    std::cout << "address of ft: " << (void*)(&ft) << std::endl;
} 

int main() 
{
    tuple<int, int> t; 
    std::cout << "address of t: " << (void*)(&t) << std::endl;
    f(t);
}

I'll add this as additional motivation for LWG 2549. Suspending the bug for
now, until LWG gives guidance.
Comment 3 Ville Voutilainen 2017-03-30 10:51:03 UTC
It seems to me that the current semantics of inherited constructors cause the base constructor that would take a tuple to not be inherited. clang+libc++ agree. I think this is thus invalid.
Comment 4 Takatoshi Kondo 2017-03-31 10:16:02 UTC
Thank you for the comment. I understand.
I use perfect forwarding in this case.
Comment 5 Jonathan Wakely 2017-07-25 21:07:50 UTC
*** Bug 81527 has been marked as a duplicate of this bug. ***