如果您之前阅读过此答案,您可能需要向下滚动到下面的 ADL 版本。它得到了很大改善。
首先,一个简短而实用的版本:
#include <iostream>
#include <type_traits>
template<typename T, typename Iterator, typename=void>
struct is_iterator_of_type: std::false_type {};
template<typename T, typename Iterator>
struct is_iterator_of_type<
T,
Iterator,
typename std::enable_if<
std::is_same<
T,
typename std::iterator_traits< Iterator >::value_type
>::value
>::type
>: std::true_type {};
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
typename std::enable_if< is_iterator_of_type<int, typename Container::iterator>::value, std::ostream& >::type
{
return stream << "int container\n";
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
typename std::enable_if< is_iterator_of_type<double, typename Container::iterator>::value, std::ostream& >::type
{
return stream << "double container\n";
}
它只检测看起来有点像的东西int
和double
具有明显重载的容器。我建议更改operator<<
. ;)
一条更合适的路线(感谢@Xeo)将是这个 adl-hack。我们创建了一个辅助命名空间,我们在其中 importbegin
和end
from ,然后一些模板函数在和std
上进行参数依赖查找(如果我们没有更紧密的绑定,请查看版本),然后使用这些函数来确定我们是什么传入的可以视为 X 上的容器:begin
end
std
aux::adl_begin
#include <iostream>
#include <vector>
#include <type_traits>
#include <iterator>
#include <set>
template<typename T, typename Iterator, typename=void>
struct is_iterator_of_type: std::false_type {};
template<typename T, typename Iterator>
struct is_iterator_of_type<
T,
Iterator,
typename std::enable_if<
std::is_same<
T,
typename std::iterator_traits< Iterator >::value_type
>::value
>::type
>: std::true_type {};
namespace aux {
using std::begin;
using std::end;
template<class T>
auto adl_begin(T&& v) -> decltype(begin(std::forward<T>(v))); // no implementation
template<class T>
auto adl_end(T&& v) -> decltype(end(std::forward<T>(v))); // no implementation
}
template<typename T, typename Container, typename=void>
struct is_container_of_type: std::false_type {};
template<typename T, typename Container>
struct is_container_of_type<
T,
Container,
typename std::enable_if<
// we only want this to be used if we iterable over doubles:
is_iterator_of_type<
T,
decltype(void(aux::adl_begin(*(Container*)nullptr)), aux::adl_end(*(Container*)nullptr)) // ensure being and end work as bonus
>::value
>::type
>: std::true_type
{};
template<class Ch, class Tr, class Container>
auto operator<<( std::basic_ostream<Ch,Tr>& stream, Container const& c ) ->
typename std::enable_if<
is_container_of_type<double, Container>::value,
decltype(stream)
>::type
{
stream << "'double' container: [ ";
for(auto&& e:c)
stream << e << " ";
return stream << "]";
}
int main() {
std::cout << std::vector<double>{1,2,3} << "\n";
std::cout << std::set<double>{3.14,2.7,-10} << "\n";
double array[] = {2.5, 3.14, 5.0};
std::cout << array << "\n";
}
有了这个,不仅double
s 的数组算作容器 over double
,所以在其命名空间中定义 abegin
和end
函数的任何东西都可以返回超过 double 的迭代器,该迭代器将容器作为参数也可以工作。这与for(auto&& i:container)
查找的工作方式相匹配(完美?相当好?),“容器”的良好定义也是如此。
但是请注意,随着我们添加更多这些装饰,具有我们正在使用的所有 C++11 功能的当前编译器将越来越少。我相信以上在 gcc 4.6 中编译,但不是 gcc 4.5.*。
...
这是原始的短代码,周围有一些测试框架:(如果你的编译器抛出它很有用,你可以在下面看到它出错的地方)
#include <iostream>
#include <type_traits>
#include <vector>
#include <iostream>
#include <set>
template<typename T, typename Iterator, typename=void>
struct is_iterator_of_type: std::false_type {};
template<typename T, typename Iterator>
struct is_iterator_of_type<
T,
Iterator,
typename std::enable_if<
std::is_same<
T,
typename std::iterator_traits< Iterator >::value_type
>::value
>::type
>: std::true_type {};
void test1() {
std::cout << is_iterator_of_type<int, std::vector<int>::iterator>::value << "\n";
}
template<typename T, typename Container>
auto foo(Container const&) -> typename std::enable_if< is_iterator_of_type<T, typename Container::iterator>::value >::type
{
std::cout << "Container of int\n";
}
template<typename T>
void foo(...)
{
std::cout << "No match\n";
}
void test2() {
std::vector<int> test;
foo<int>(test);
foo<int>(test.begin());
foo<int>(std::set<int>());
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
typename std::enable_if< is_iterator_of_type<int, typename Container::iterator>::value, std::ostream& >::type
{
return stream << "int container\n";
}
void test3() {
std::vector<int> test;
std::cout << test;
std::set<int> bar;
std::cout << bar;
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
typename std::enable_if< is_iterator_of_type<double, typename Container::iterator>::value, std::ostream& >::type
{
return stream << "double container\n";
}
void test4() {
std::vector<int> test;
std::cout << test;
std::set<int> bar;
std::cout << bar;
std::vector<double> dtest;
std::cout << dtest;
}
void test5() {
std::vector<bool> test;
// does not compile (naturally):
// std::cout << test;
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
typename std::enable_if< is_iterator_of_type<bool, typename Container::iterator>::value, std::ostream& >::type
{
return stream << "bool container\n";
}
void test6() {
std::vector<bool> test;
// now compiles:
std::cout << test;
}
int main() {
test1();
test2();
test3();
test4();
test5();
test6();
}
以上大约一半是测试样板。is_iterator_of_type
模板和operator<<
重载是您想要的。
我假设类型容器T
是任何具有 typedef 的类iterator
,其value_type
类型为T
. 这将涵盖每个std
容器,以及大多数自定义容器。
执行运行链接:http: //ideone.com/lMUF4i——请注意,一些编译器不支持完整的 C++11 SFINAE,可能需要 tomfoolery 才能使其工作。
留下的测试用例可以帮助某人检查他们的编译器对这些技术的支持程度。