我有一个ID
带有参数的类模板T
。
- 如果
T
已key_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<()
。