C++ 编译问题:使用元组构建复合密钥可变模板类

C++ 编译问题:使用元组构建复合密钥可变模板类,c++,c++11,tuples,variadic-templates,C++,C++11,Tuples,Variadic Templates,我有一个ID类模板,它接受一个参数T 如果T定义了key\u类型,ID对类型为T的对象调用get\u key() 如果T没有定义key\u type,ID将使用对象的地址作为标识符 到目前为止,代码运行良好 现在,我想定义一个新的可变类模板Composite_Key,它将可变模板参数作为std::tuple。我正试图让这段新代码与ID一起工作,但我遇到了一大堆编译错误,我很难理解这些错误 这些错误似乎表明缺少操作符,您需要实现操作符,这需要阅读大量痛苦的代码。你真的不能把它简化成一个简单的例

我有一个
ID
类模板,它接受一个参数
T

  • 如果
    T
    定义了
    key\u类型
    ID
    对类型为
    T
    的对象调用
    get\u key()
    
  • 如果
    T
    没有定义
    key\u type
    ID
    将使用对象的地址作为标识符
到目前为止,代码运行良好

现在,我想定义一个新的可变类模板
Composite_Key
,它将可变模板参数作为
std::tuple
。我正试图让这段新代码与
ID
一起工作,但我遇到了一大堆编译错误,我很难理解这些错误


这些错误似乎表明缺少
操作符,您需要实现
操作符,这需要阅读大量痛苦的代码。你真的不能把它简化成一个简单的例子吗?+1-是的:很好用!我想让我失望的是,我(错误地)认为
操作员
#include <string>
#include <tuple>
#include <set>
#include <cassert>

template<typename T>
struct void_ {
    using type = void;
};

// -----------------------------------------------------------------------------

template<typename T, typename = void>
struct ptr_or_key_type {
    using type = T const*;               // our default key_type : a ptr
    static type get_key( T const& t ) { return &t; }
};

template<typename T>
struct ptr_or_key_type<T, typename void_<typename T::key_type>::type> {
    using type = typename T::key_type;   // the specialised key_type
    static type get_key( T const& t ) { return t.get_key(); }
};

// -----------------------------------------------------------------------------

template<typename T>
class ID
{
private:
  typename ptr_or_key_type<T>::type   m_id;

public:
    ID( T const& t ) :
        m_id( ptr_or_key_type<T>::get_key( t ))
    { }
    ID( ID const& rhs ) :
        m_id( rhs.m_id )
    { }
    ~ID() { }
    ID& operator=( ID const& rhs )
    {
        if ( &rhs!=this )
            m_id = rhs.m_id;
        return *this;
    }
public:
    bool operator==( ID const& rhs ) const { return m_id==rhs.m_id; }
    bool operator!=( ID const& rhs ) const { return !(*this==rhs);  }
    bool operator<( ID const& rhs ) const  { return m_id<rhs.m_id;  }
    bool operator<=( ID const& rhs ) const { return m_id<=rhs.m_id; }
    bool operator>( ID const& rhs ) const  { return m_id>rhs.m_id;  }
    bool operator>=( ID const& rhs ) const { return m_id>=rhs.m_id; }
};

// -----------------------------------------------------------------------------

struct Plain_Class { };

struct String_Key { 
    using key_type = std::string;

    std::string  m_key;
    String_Key( std::string const& key ) : m_key( key ) { }
    std::string const& 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<typename... Args>
struct Composite_Key
{
  using key_type = std::tuple<Args...>;

    key_type m_key;
    Composite_Key( key_type const& key ) : m_key( key ) { }
    key_type const& 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<Plain_Class> id_f( f ), id_g( g );
    assert( id_f!=id_g );
    std::set<ID<Plain_Class>>  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<ID<String_Key>>  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<String_Key,Int_Key,Char_Key>; 
    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<ID<My_Composite>>  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
}
In file included from sandbox.cpp:2:0:
/usr/include/c++/4.7/tuple: In instantiation of ‘static bool std::__tuple_compare<0ul, __i, __j, _Tp, _Up>::__less(const _Tp&, const _Up&) [with long unsigned int __i = 0ul; long unsigned int __j = 3ul; _Tp = std::tuple<String_Key, Int_Key, Char_Key>; _Up = std::tuple<String_Key, Int_Key, Char_Key>]’:
/usr/include/c++/4.7/tuple:814:62:   required from ‘bool std::operator<(const std::tuple<_TElements ...>&, const std::tuple<_Elements ...>&) [with _TElements = {String_Key, Int_Key, Char_Key}; _UElements = {String_Key, Int_Key, Char_Key}]’
sandbox.cpp:50:59:   required from ‘bool ID<T>::operator<(const ID<T>&) const [with T = Composite_Key<String_Key, Int_Key, Char_Key>; ID<T> = ID<Composite_Key<String_Key, Int_Key, Char_Key> >]’
/usr/include/c++/4.7/bits/stl_function.h:237:22:   required from ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = ID<Composite_Key<String_Key, Int_Key, Char_Key> >]’
/usr/include/c++/4.7/bits/stl_tree.h:1285:4:   required from ‘std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_Arg&&) [with _Arg = ID<Composite_Key<String_Key, Int_Key, Char_Key> >; _Key = ID<Composite_Key<String_Key, Int_Key, Char_Key> >; _Val = ID<Composite_Key<String_Key, Int_Key, Char_Key> >; _KeyOfValue = std::_Identity<ID<Composite_Key<String_Key, Int_Key, Char_Key> > >; _Compare = std::less<ID<Composite_Key<String_Key, Int_Key, Char_Key> > >; _Alloc = std::allocator<ID<Composite_Key<String_Key, Int_Key, Char_Key> > >]’
/usr/include/c++/4.7/bits/stl_set.h:424:40:   required from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(std::set<_Key, _Compare, _Alloc>::value_type&&) [with _Key = ID<Composite_Key<String_Key, Int_Key, Char_Key> >; _Compare = std::less<ID<Composite_Key<String_Key, Int_Key, Char_Key> > >; _Alloc = std::allocator<ID<Composite_Key<String_Key, Int_Key, Char_Key> > >; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<ID<Composite_Key<String_Key, Int_Key, Char_Key> > >; std::set<_Key, _Compare, _Alloc>::value_type = ID<Composite_Key<String_Key, Int_Key, Char_Key> >]’
sandbox.cpp:121:15:   required from here
/usr/include/c++/4.7/tuple:781:63: error: no match for ‘operator<’ in ‘std::get<0ul, {String_Key, Int_Key, Char_Key}>((* & __u)) < std::get<0ul, {String_Key, Int_Key, Char_Key}>((* & __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<class _T1, class _T2> constexpr bool std::operator<(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&)
/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<_T1, _T2>’
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<class _Iterator> bool std::operator<(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)
/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<_Iterator>’
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<class _IteratorL, class _IteratorR> bool std::operator<(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorR>&)
/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<_IteratorL>’
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<class _IteratorL, class _IteratorR> bool std::operator<(const std::move_iterator<_IteratorL>&, const std::move_iterator<_IteratorR>&)
/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<_IteratorL>’
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<class _Iterator> bool std::operator<(const std::move_iterator<_Iterator>&, const std::move_iterator<_Iterator>&)
/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<_Iterator>’
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<class _CharT, class _Traits, class _Alloc> bool std::operator<(const std::basic_string<_CharT, _Traits, _Alloc>&, const std::basic_string<_CharT, _Traits, _Alloc>&)
/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<_CharT, _Traits, _Alloc>’
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<class _CharT, class _Traits, class _Alloc> bool std::operator<(const std::basic_string<_CharT, _Traits, _Alloc>&, 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<_CharT, _Traits, _Alloc>’
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<class _CharT, class _Traits, class _Alloc> bool std::operator<(const _CharT*, const std::basic_string<_CharT, _Traits, _Alloc>&)
/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<class ... _TElements, class ... _UElements> bool std::operator<(const std::tuple<_TElements ...>&, const std::tuple<_Elements ...>&)
/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<_TElements ...>’
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<class _Key, class _Val, class _KeyOfValue, class _Compare, class _Alloc> bool std::operator<(const std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&, const std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&)
/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<_Key, _Val, _KeyOfValue, _Compare, _Alloc>’
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<class _Key, class _Compare, class _Alloc> bool std::operator<(const std::set<_Key, _Compare, _Alloc>&, const std::set<_Key, _Compare, _Alloc>&)
/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<_Key, _Compare, _Alloc>’
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<class _Key, class _Compare, class _Alloc> bool std::operator<(const std::multiset<_Key, _Compare, _Alloc>&, const std::multiset<_Key, _Compare, _Alloc>&)
/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<_Key, _Compare, _Alloc>’
/usr/include/c++/4.7/tuple:781:63: error: no match for ‘operator<’ in ‘std::get<0ul, {String_Key, Int_Key, Char_Key}>((* & __t)) < std::get<0ul, {String_Key, Int_Key, Char_Key}>((* & __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<class _T1, class _T2> constexpr bool std::operator<(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&)
/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<_T1, _T2>’
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<class _Iterator> bool std::operator<(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)
/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<_Iterator>’
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<class _IteratorL, class _IteratorR> bool std::operator<(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorR>&)
/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<_IteratorL>’
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<class _IteratorL, class _IteratorR> bool std::operator<(const std::move_iterator<_IteratorL>&, const std::move_iterator<_IteratorR>&)
/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<_IteratorL>’
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<class _Iterator> bool