3

如果我有一个类型T,那么在编译时检查它以查看它是否是 STL 样式容器(对于任意值类型)的有用方法是什么?
(假设:指针、引用等已经被剥离)

起始代码:

template<class T> // (1)
void f(T&) {} 

template<class T> // (2)
void f(std::vector<T>&) {} 

void test() 
{
    int a;
    std::vector<int> b;
    f(a);
    f(b);
}

现在这工作正常,但如果我想概括容器(即不定义(3)(4),...明确)?

使用SFINAE和类型列表会在一定程度上减少代码,但有更好的方法吗?
或者是否有基于概念的专业习语?
或者我可以以某种方式利用 SFINAE 来选择性地启用所需的专业化吗?

作为旁注,我不能使用迭代器 - 我正在尝试基于接收Ts 作为参数的函数进行专门化。


根据MSalters 的回答

template<class T>
void f(T&, ...) {
    std::cout << "flat" << std::endl; 
}

template<class Cont>
void f(Cont& c, typename Cont::iterator begin = Cont().begin(),
                typename Cont::iterator end   = Cont().end()) {
    std::cout << "container" << std::endl; 
}

(需要变量参数列表来使第一个f成为最不喜欢的版本来解决歧义错误)

4

3 回答 3

2

根据定义,STLcontainers 有一个 typedef iterator,有 2 个方法begin()end()重新运行它们。这个范围容器所包含的。如果没有这样的范围,它就不是 STL 意义上的容器。所以我建议沿线(未检查)

template<typename CONTAINER>
void f(CONTAINER& c,
       typename CONTAINER::iterator begin = c.begin(),
       typename CONTAINER::iterator end = c.end())
{ }
于 2009-12-15T10:51:12.207 回答
2

你所做的任何事情几乎肯定都是极其脆弱的。什么是或不是“STL”之间根本没有明确的分界线。即使有一条清晰的分界线,在任何情况下,这种决定几乎肯定是一个非常糟糕的基础。举例来说,如果我编写(或使用)使用 AVL 树而不是更常见的 RB 树的 std::map 的重新实现,为什么要区别对待 std::map?

在散列容器的情况下,从 hash_map 的各种实现,到 Boost 容器,到 TR1 容器,再到将包含在 C++ 0x 标准库中的容器,都有一个完整的进展。根据您对“STL”的定义,很有可能其中至少有一个不是 STL,而另一个是,但没有任何一点可能有意义地将一个与另一个区别对待。

我认为您应该考虑容器的特性,然后尝试确定对您真正重要的特性。

于 2009-12-15T03:07:59.767 回答
0

根据www.cplusplus.com,所有 STL 容器共有的唯一功能是:

  • 一个构造函数
  • operator=
  • size.

在编译时,您可以确定这些运算符是否存在于您的 typeT中。

于 2009-12-15T02:44:51.233 回答