0

我有一个ID带有参数的类模板T

  • 如果Tkey_type定义,则ID调用get_key()类型的对象T以获取用于存储的标识符。
  • 如果T没有key_type定义,ID将使用对象的地址作为标识符。

到目前为止,代码工作正常。

现在,我想定义一个新的可变参数类模板Composite_Key,它将可变参数模板参数作为std::tuple. 我正在尝试使用此新代码ID,但我遇到了一堆编译错误,我很难理解。

这些错误似乎表明缺少operator<(),这很奇怪,因为它是在 ; 中定义的ID。我不知道我做错了什么。

下面的代码,包括测试代码,在最后一行(注释)之前都可以正常工作。

代码

#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 

回答

正如下面的 jmetcalf所指出的,所有的 Key 类也必须实现operator<()。这是有道理的,因为operator<()inID实际上取决于std::tuple's operator<(),这取决于所有单独的类型' operator<()

4

1 回答 1

2

operator<()如果你想在集合中使用它们,你需要在你的关键类中实现它们。实现要求对所有子类型都实现这std::tuple::operator<()一点(它按字典顺序从左到右进行比较)

一旦你从其他不相关的东西中挑选出来,这个错误就很明显了:

/usr/include/c++/4.7/tuple:781:63: 错误: 'std::get< 0 ul, { String_Key , Int_Key, Char_Key}>((* & __u )) < std::get< 0 ul, { String_Key , Int_Key, Char_Key}>((* & __t))'</p>

于 2013-02-13T18:53:22.813 回答