static_assert()的优雅方式是订购标准库容器类型?

时间:2014-02-10 16:45:35

标签: c++ templates c++11 stl static-assert

在模板化函数中,其中一个参数是T类型的标准库容器,我可以轻松静态断言T是一个有序容器吗?

是否有更优雅的方法来执行此操作,而不是执行特定于类型的操作,例如测试是否存在hash_function()函数以区分std::mapstd::unordered_map

4 个答案:

答案 0 :(得分:3)

另一个简单的问题:

template <template <typename...> class Container>
struct is_ordered : std::false_type {};

template <> struct is_ordered<std::map>      : std::true_type {};
template <> struct is_ordered<std::set>      : std::true_type {};
template <> struct is_ordered<std::multimap> : std::true_type {};
template <> struct is_ordered<std::multiset> : std::true_type {};

然后只需static_assert(is_ordered<Container>::value, "error")即可使用它。扩展到自定义容器也很容易:只需添加如上所示的行。

如果您不想在呼叫站点使用模板模板,您可以始终将其包装为ala:

template <typename T> struct is_ordered_2 : std::false_type {};
template <template <typename...> class Container, typename... Ts>
struct is_ordered_2<Container<Ts...>> : is_ordered<Container> {};

然后你可以使用它。

答案 1 :(得分:1)

这种方法非常简单:

// default result
template<class T>constexpr bool IsOrdered(const T&) {return false;}

// now enumerate the ordered standard library types of interest:
template<class K, class T, class C, class A>
constexpr bool IsOrdered(const std::map<K,T,C,A>&) {return true;}
// ...remaining types...

答案 2 :(得分:0)

例如,如果您只关注禁止使用std::unordered_mapstd::unordered_set这样的特定类,则可以使用与static_assert一致的类型特征:

#include <type_traits>
#include <unordered_map>
#include <unordered_set>

template <typename Container, typename T>
void func(Container<T> &c)
{
    // make sure that the provided container isn't a type we don't want!
    static_assert(!std::is_same<Container<T>, std::unordered_map<T>>::value);
    static_assert(!std::is_same<Container<T>, std::unordered_set<T>>::value);
}

我不确定这是否符合原始问题的“特定类型”。您根本没有查看禁止类的内部(例如查找hash_function(),但此方法需要您枚举您不想使用的容器。

答案 3 :(得分:0)

你可以(强调可以,因为我不认为它是标准的)做这样的事情:

template <typename T>
struct has_typedef_key_compare 
{
  // Types "yes" and "no" are guaranteed to have different sizes,
  // specifically sizeof(yes) == 1 and sizeof(no) == 2.
  typedef char yes[1];
  typedef char no[2];

  template <typename C>
  static yes& test(typename C::key_compare*);

  template <typename>
  static no& test(...);

  // If the "sizeof" of the result of calling test<T>(0) would be equal to sizeof(yes),
  // the first overload worked and T has a nested type named foobar.
  static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};

template <typename T>
struct is_sorted_container
{
  static const bool value;
};

template <typename T>
const bool is_sorted_container<T>::value = has_typedef_key_compare<T>::value;

基本原理是所有已排序的stl容器(我看过)都有一个key_compare函数。当然,这不是标准。这不会涵盖非stl类型。总而言之,我不喜欢它,但我认为我会把它作为一个有趣的替代品发布。

stl函数(如std :: upper_bound)如何解决这个问题是将排序迭代器的限制放在注释中,让最终用户弄明白。