2013-02-13 78 views
0

我有一个ID类模板,它需要参数T编译问题:使用元组构建Composite_Key variadic模板类

  • 如果T具有T类型的对象上定义的key_typeID呼叫get_key()获得用于存储的标识符。
  • 如果T没有定义key_type,则ID将使用该对象的地址作为标识符。

该代码正常工作到这一点。

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

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

下面的代码,包括测试代码,直到最后一行(注释)都能正常工作。错误

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 

ANSWER

正如jmetcalf below指明,

CODE

#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 
} 

墙,所有的重点班也必须实现operator<()。这是有道理的,因为operator<()ID实际上取决于std::tupleoperator<(),这取决于所有的个人类型'operator<()

+0

这是一个痛苦的很多代码来通读。你真的不能减少这个更简单的例子? – 2013-02-13 18:43:01

回答

2

如果你想在集合中使用它们,你需要在你的关键类中实现operator<()。该std::tuple::operator<()实施要求,这是对所有的子类实现的(它字典顺序比较左至右)

,一旦你把它挑出来的其他不相关的东西的错误是很明显的:

/usr/include/c++/4.7/tuple:781:63: error: no match for ‘operator<’ in ‘std::get<0 ul, {String_Key, Int_Key, Char_Key}>((* & __u)) < std::get<0 ul, {String_Key, Int_Key, Char_Key}>((* & __t))’

+0

+1 - 很好用!我认为是什么把我扔掉了,我想(错误地)在'ID'中定义的'operator <()'是足够的。 TYVM。 – kfmfe04 2013-02-13 19:01:42