Note that there are some explanatory texts on larger screens.

plurals
  1. POCompile problems: building a Composite_Key variadic template class using tuples
    primarykey
    data
    text
    <p>I have an <code>ID</code> class template that takes a parameter <code>T</code>. </p> <ul> <li>If <code>T</code> has a <code>key_type</code> defined, <code>ID</code> calls <code>get_key()</code> on an object of type <code>T</code> to get the identifier for storage. </li> <li>If <code>T</code> does not have <code>key_type</code> defined, <code>ID</code> will use the address of the object as the identifier.</li> </ul> <p>The code works fine up to this point.</p> <p>Now, I would like to define a new variadic class template <code>Composite_Key</code> which takes variadic template parameters as a <code>std::tuple</code>. I am trying to get this new code to work with <code>ID</code>, but I am getting a wall of compilation errors that I am having a hard time understanding.</p> <p>The errors seem to indicate a missing <code>operator&lt;()</code>, which is odd because it's defined in <code>ID</code>; I'm at a loss as to what I'm doing wrong.</p> <p>The code below, including test code, works fine up until that last line (commented).</p> <p><strong>CODE</strong></p> <pre><code>#include &lt;string&gt; #include &lt;tuple&gt; #include &lt;set&gt; #include &lt;cassert&gt; template&lt;typename T&gt; struct void_ { using type = void; }; // ----------------------------------------------------------------------------- template&lt;typename T, typename = void&gt; struct ptr_or_key_type { using type = T const*; // our default key_type : a ptr static type get_key( T const&amp; t ) { return &amp;t; } }; template&lt;typename T&gt; struct ptr_or_key_type&lt;T, typename void_&lt;typename T::key_type&gt;::type&gt; { using type = typename T::key_type; // the specialised key_type static type get_key( T const&amp; t ) { return t.get_key(); } }; // ----------------------------------------------------------------------------- template&lt;typename T&gt; class ID { private: typename ptr_or_key_type&lt;T&gt;::type m_id; public: ID( T const&amp; t ) : m_id( ptr_or_key_type&lt;T&gt;::get_key( t )) { } ID( ID const&amp; rhs ) : m_id( rhs.m_id ) { } ~ID() { } ID&amp; operator=( ID const&amp; rhs ) { if ( &amp;rhs!=this ) m_id = rhs.m_id; return *this; } public: bool operator==( ID const&amp; rhs ) const { return m_id==rhs.m_id; } bool operator!=( ID const&amp; rhs ) const { return !(*this==rhs); } bool operator&lt;( ID const&amp; rhs ) const { return m_id&lt;rhs.m_id; } bool operator&lt;=( ID const&amp; rhs ) const { return m_id&lt;=rhs.m_id; } bool operator&gt;( ID const&amp; rhs ) const { return m_id&gt;rhs.m_id; } bool operator&gt;=( ID const&amp; rhs ) const { return m_id&gt;=rhs.m_id; } }; // ----------------------------------------------------------------------------- struct Plain_Class { }; struct String_Key { using key_type = std::string; std::string m_key; String_Key( std::string const&amp; key ) : m_key( key ) { } std::string const&amp; get_key() const { return m_key; } }; struct Char_Key { using key_type = char; char m_key; Char_Key( char key ) : m_key( key ) { } char get_key() const { return m_key; } }; struct Int_Key { using key_type = int; int m_key; Int_Key( int key ) : m_key( key ) { } int get_key() const { return m_key; } }; template&lt;typename... Args&gt; struct Composite_Key { using key_type = std::tuple&lt;Args...&gt;; key_type m_key; Composite_Key( key_type const&amp; key ) : m_key( key ) { } key_type const&amp; get_key() const { return m_key; } }; // ----------------------------------------------------------------------------- int main( int argc, char* argv[] ) { // Plain_Class will use address of object as key Plain_Class f,g; ID&lt;Plain_Class&gt; id_f( f ), id_g( g ); assert( id_f!=id_g ); std::set&lt;ID&lt;Plain_Class&gt;&gt; s; s.insert( f ); s.insert( g ); assert( s.size()==2u ); // two unique addresses, so two in the set // String_Key will use std::string as the key String_Key h( "abc" ), i( "abc" ); std::set&lt;ID&lt;String_Key&gt;&gt; s2; s2.insert( h ); s2.insert( i ); assert( s2.size()==1u ); // since sets must have unique values // attempt a composite key type using My_Composite = Composite_Key&lt;String_Key,Int_Key,Char_Key&gt;; My_Composite j( std::make_tuple( String_Key{ "foo" }, Int_Key{ 1 }, Char_Key{ 'c' } )), k( std::make_tuple( String_Key{ "foo" }, Int_Key{ 1 }, Char_Key{ 'c' } )) ; std::set&lt;ID&lt;My_Composite&gt;&gt; s3; s3.insert( j ); // FAILURE: everything above this line compiles fine #if 0 s3.insert( k ); assert( s3.size()==1u ); // since sets must have unique values #endif } </code></pre> <p><strong>WALL OF ERRORS</strong></p> <pre><code>In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple: In instantiation of ‘static bool std::__tuple_compare&lt;0ul, __i, __j, _Tp, _Up&gt;::__less(const _Tp&amp;, const _Up&amp;) [with long unsigned int __i = 0ul; long unsigned int __j = 3ul; _Tp = std::tuple&lt;String_Key, Int_Key, Char_Key&gt;; _Up = std::tuple&lt;String_Key, Int_Key, Char_Key&gt;]’: /usr/include/c++/4.7/tuple:814:62: required from ‘bool std::operator&lt;(const std::tuple&lt;_TElements ...&gt;&amp;, const std::tuple&lt;_Elements ...&gt;&amp;) [with _TElements = {String_Key, Int_Key, Char_Key}; _UElements = {String_Key, Int_Key, Char_Key}]’ sandbox.cpp:50:59: required from ‘bool ID&lt;T&gt;::operator&lt;(const ID&lt;T&gt;&amp;) const [with T = Composite_Key&lt;String_Key, Int_Key, Char_Key&gt;; ID&lt;T&gt; = ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt;]’ /usr/include/c++/4.7/bits/stl_function.h:237:22: required from ‘bool std::less&lt;_Tp&gt;::operator()(const _Tp&amp;, const _Tp&amp;) const [with _Tp = ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt;]’ /usr/include/c++/4.7/bits/stl_tree.h:1285:4: required from ‘std::pair&lt;std::_Rb_tree_iterator&lt;_Val&gt;, bool&gt; std::_Rb_tree&lt;_Key, _Val, _KeyOfValue, _Compare, _Alloc&gt;::_M_insert_unique(_Arg&amp;&amp;) [with _Arg = ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt;; _Key = ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt;; _Val = ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt;; _KeyOfValue = std::_Identity&lt;ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt; &gt;; _Compare = std::less&lt;ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt; &gt;; _Alloc = std::allocator&lt;ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt; &gt;]’ /usr/include/c++/4.7/bits/stl_set.h:424:40: required from ‘std::pair&lt;typename std::_Rb_tree&lt;_Key, _Key, std::_Identity&lt;_Key&gt;, _Compare, typename _Alloc::rebind&lt;_Key&gt;::other&gt;::const_iterator, bool&gt; std::set&lt;_Key, _Compare, _Alloc&gt;::insert(std::set&lt;_Key, _Compare, _Alloc&gt;::value_type&amp;&amp;) [with _Key = ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt;; _Compare = std::less&lt;ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt; &gt;; _Alloc = std::allocator&lt;ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt; &gt;; typename std::_Rb_tree&lt;_Key, _Key, std::_Identity&lt;_Key&gt;, _Compare, typename _Alloc::rebind&lt;_Key&gt;::other&gt;::const_iterator = std::_Rb_tree_const_iterator&lt;ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt; &gt;; std::set&lt;_Key, _Compare, _Alloc&gt;::value_type = ID&lt;Composite_Key&lt;String_Key, Int_Key, Char_Key&gt; &gt;]’ sandbox.cpp:121:15: required from here /usr/include/c++/4.7/tuple:781:63: error: no match for ‘operator&lt;’ in ‘std::get&lt;0ul, {String_Key, Int_Key, Char_Key}&gt;((* &amp; __u)) &lt; std::get&lt;0ul, {String_Key, Int_Key, Char_Key}&gt;((* &amp; __t))’ /usr/include/c++/4.7/tuple:781:63: note: candidates are: In file included from /usr/include/c++/4.7/bits/stl_algobase.h:65:0, from /usr/include/c++/4.7/bits/char_traits.h:41, from /usr/include/c++/4.7/string:42, from sandbox.cpp:1: /usr/include/c++/4.7/bits/stl_pair.h:212:5: note: template&lt;class _T1, class _T2&gt; constexpr bool std::operator&lt;(const std::pair&lt;_T1, _T2&gt;&amp;, const std::pair&lt;_T1, _T2&gt;&amp;) /usr/include/c++/4.7/bits/stl_pair.h:212:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::pair&lt;_T1, _T2&gt;’ In file included from /usr/include/c++/4.7/bits/stl_algobase.h:68:0, from /usr/include/c++/4.7/bits/char_traits.h:41, from /usr/include/c++/4.7/string:42, from sandbox.cpp:1: /usr/include/c++/4.7/bits/stl_iterator.h:299:5: note: template&lt;class _Iterator&gt; bool std::operator&lt;(const std::reverse_iterator&lt;_Iterator&gt;&amp;, const std::reverse_iterator&lt;_Iterator&gt;&amp;) /usr/include/c++/4.7/bits/stl_iterator.h:299:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::reverse_iterator&lt;_Iterator&gt;’ In file included from /usr/include/c++/4.7/bits/stl_algobase.h:68:0, from /usr/include/c++/4.7/bits/char_traits.h:41, from /usr/include/c++/4.7/string:42, from sandbox.cpp:1: /usr/include/c++/4.7/bits/stl_iterator.h:349:5: note: template&lt;class _IteratorL, class _IteratorR&gt; bool std::operator&lt;(const std::reverse_iterator&lt;_IteratorL&gt;&amp;, const std::reverse_iterator&lt;_IteratorR&gt;&amp;) /usr/include/c++/4.7/bits/stl_iterator.h:349:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::reverse_iterator&lt;_IteratorL&gt;’ In file included from /usr/include/c++/4.7/bits/stl_algobase.h:68:0, from /usr/include/c++/4.7/bits/char_traits.h:41, from /usr/include/c++/4.7/string:42, from sandbox.cpp:1: /usr/include/c++/4.7/bits/stl_iterator.h:1057:5: note: template&lt;class _IteratorL, class _IteratorR&gt; bool std::operator&lt;(const std::move_iterator&lt;_IteratorL&gt;&amp;, const std::move_iterator&lt;_IteratorR&gt;&amp;) /usr/include/c++/4.7/bits/stl_iterator.h:1057:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::move_iterator&lt;_IteratorL&gt;’ In file included from /usr/include/c++/4.7/bits/stl_algobase.h:68:0, from /usr/include/c++/4.7/bits/char_traits.h:41, from /usr/include/c++/4.7/string:42, from sandbox.cpp:1: /usr/include/c++/4.7/bits/stl_iterator.h:1063:5: note: template&lt;class _Iterator&gt; bool std::operator&lt;(const std::move_iterator&lt;_Iterator&gt;&amp;, const std::move_iterator&lt;_Iterator&gt;&amp;) /usr/include/c++/4.7/bits/stl_iterator.h:1063:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::move_iterator&lt;_Iterator&gt;’ In file included from /usr/include/c++/4.7/string:54:0, from sandbox.cpp:1: /usr/include/c++/4.7/bits/basic_string.h:2566:5: note: template&lt;class _CharT, class _Traits, class _Alloc&gt; bool std::operator&lt;(const std::basic_string&lt;_CharT, _Traits, _Alloc&gt;&amp;, const std::basic_string&lt;_CharT, _Traits, _Alloc&gt;&amp;) /usr/include/c++/4.7/bits/basic_string.h:2566:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::basic_string&lt;_CharT, _Traits, _Alloc&gt;’ In file included from /usr/include/c++/4.7/string:54:0, from sandbox.cpp:1: /usr/include/c++/4.7/bits/basic_string.h:2578:5: note: template&lt;class _CharT, class _Traits, class _Alloc&gt; bool std::operator&lt;(const std::basic_string&lt;_CharT, _Traits, _Alloc&gt;&amp;, const _CharT*) /usr/include/c++/4.7/bits/basic_string.h:2578:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::basic_string&lt;_CharT, _Traits, _Alloc&gt;’ In file included from /usr/include/c++/4.7/string:54:0, from sandbox.cpp:1: /usr/include/c++/4.7/bits/basic_string.h:2590:5: note: template&lt;class _CharT, class _Traits, class _Alloc&gt; bool std::operator&lt;(const _CharT*, const std::basic_string&lt;_CharT, _Traits, _Alloc&gt;&amp;) /usr/include/c++/4.7/bits/basic_string.h:2590:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: mismatched types ‘const _CharT*’ and ‘String_Key’ /usr/include/c++/4.7/tuple:808:5: note: template&lt;class ... _TElements, class ... _UElements&gt; bool std::operator&lt;(const std::tuple&lt;_TElements ...&gt;&amp;, const std::tuple&lt;_Elements ...&gt;&amp;) /usr/include/c++/4.7/tuple:808:5: note: template argument deduction/substitution failed: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::tuple&lt;_TElements ...&gt;’ In file included from /usr/include/c++/4.7/set:60:0, from sandbox.cpp:3: /usr/include/c++/4.7/bits/stl_tree.h:873:5: note: template&lt;class _Key, class _Val, class _KeyOfValue, class _Compare, class _Alloc&gt; bool std::operator&lt;(const std::_Rb_tree&lt;_Key, _Val, _KeyOfValue, _Compare, _Alloc&gt;&amp;, const std::_Rb_tree&lt;_Key, _Val, _KeyOfValue, _Compare, _Alloc&gt;&amp;) /usr/include/c++/4.7/bits/stl_tree.h:873:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::_Rb_tree&lt;_Key, _Val, _KeyOfValue, _Compare, _Alloc&gt;’ In file included from /usr/include/c++/4.7/set:61:0, from sandbox.cpp:3: /usr/include/c++/4.7/bits/stl_set.h:721:5: note: template&lt;class _Key, class _Compare, class _Alloc&gt; bool std::operator&lt;(const std::set&lt;_Key, _Compare, _Alloc&gt;&amp;, const std::set&lt;_Key, _Compare, _Alloc&gt;&amp;) /usr/include/c++/4.7/bits/stl_set.h:721:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::set&lt;_Key, _Compare, _Alloc&gt;’ In file included from /usr/include/c++/4.7/set:62:0, from sandbox.cpp:3: /usr/include/c++/4.7/bits/stl_multiset.h:702:5: note: template&lt;class _Key, class _Compare, class _Alloc&gt; bool std::operator&lt;(const std::multiset&lt;_Key, _Compare, _Alloc&gt;&amp;, const std::multiset&lt;_Key, _Compare, _Alloc&gt;&amp;) /usr/include/c++/4.7/bits/stl_multiset.h:702:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::multiset&lt;_Key, _Compare, _Alloc&gt;’ /usr/include/c++/4.7/tuple:781:63: error: no match for ‘operator&lt;’ in ‘std::get&lt;0ul, {String_Key, Int_Key, Char_Key}&gt;((* &amp; __t)) &lt; std::get&lt;0ul, {String_Key, Int_Key, Char_Key}&gt;((* &amp; __u))’ /usr/include/c++/4.7/tuple:781:63: note: candidates are: In file included from /usr/include/c++/4.7/bits/stl_algobase.h:65:0, from /usr/include/c++/4.7/bits/char_traits.h:41, from /usr/include/c++/4.7/string:42, from sandbox.cpp:1: /usr/include/c++/4.7/bits/stl_pair.h:212:5: note: template&lt;class _T1, class _T2&gt; constexpr bool std::operator&lt;(const std::pair&lt;_T1, _T2&gt;&amp;, const std::pair&lt;_T1, _T2&gt;&amp;) /usr/include/c++/4.7/bits/stl_pair.h:212:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::pair&lt;_T1, _T2&gt;’ In file included from /usr/include/c++/4.7/bits/stl_algobase.h:68:0, from /usr/include/c++/4.7/bits/char_traits.h:41, from /usr/include/c++/4.7/string:42, from sandbox.cpp:1: /usr/include/c++/4.7/bits/stl_iterator.h:299:5: note: template&lt;class _Iterator&gt; bool std::operator&lt;(const std::reverse_iterator&lt;_Iterator&gt;&amp;, const std::reverse_iterator&lt;_Iterator&gt;&amp;) /usr/include/c++/4.7/bits/stl_iterator.h:299:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::reverse_iterator&lt;_Iterator&gt;’ In file included from /usr/include/c++/4.7/bits/stl_algobase.h:68:0, from /usr/include/c++/4.7/bits/char_traits.h:41, from /usr/include/c++/4.7/string:42, from sandbox.cpp:1: /usr/include/c++/4.7/bits/stl_iterator.h:349:5: note: template&lt;class _IteratorL, class _IteratorR&gt; bool std::operator&lt;(const std::reverse_iterator&lt;_IteratorL&gt;&amp;, const std::reverse_iterator&lt;_IteratorR&gt;&amp;) /usr/include/c++/4.7/bits/stl_iterator.h:349:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::reverse_iterator&lt;_IteratorL&gt;’ In file included from /usr/include/c++/4.7/bits/stl_algobase.h:68:0, from /usr/include/c++/4.7/bits/char_traits.h:41, from /usr/include/c++/4.7/string:42, from sandbox.cpp:1: /usr/include/c++/4.7/bits/stl_iterator.h:1057:5: note: template&lt;class _IteratorL, class _IteratorR&gt; bool std::operator&lt;(const std::move_iterator&lt;_IteratorL&gt;&amp;, const std::move_iterator&lt;_IteratorR&gt;&amp;) /usr/include/c++/4.7/bits/stl_iterator.h:1057:5: note: template argument deduction/substitution failed: In file included from sandbox.cpp:2:0: /usr/include/c++/4.7/tuple:781:63: note: ‘const String_Key’ is not derived from ‘const std::move_iterator&lt;_IteratorL&gt;’ In file included from /usr/include/c++/4.7/bits/stl_algobase.h:68:0, from /usr/include/c++/4.7/bits/char_traits.h:41, from /usr/include/c++/4.7/string:42, from sandbox.cpp:1: /usr/include/c++/4.7/bits/stl_iterator.h:1063:5: note: template&lt;class _Iterator&gt; bool </code></pre> <p><strong>ANSWER</strong></p> <p>As indicated by <a href="https://stackoverflow.com/a/14860850/975129">jmetcalf below</a>, all the Key classes must also implement <code>operator&lt;()</code>. This makes sense because the <code>operator&lt;()</code> in <code>ID</code> actually depends on <code>std::tuple</code>'s <code>operator&lt;()</code>, which depends on all the individual types' <code>operator&lt;()</code>.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload