Ответ 1
Поскольку для циклов, основанных на диапазонах, требуется begin(v)
и end(v)
, чтобы быть действительными с ADL (и std::
, являющимся ассоциированным пространством имен), вы можете использовать это:
namespace support_begin_end
{
// we use a special namespace (above) to
// contain the using directive for 'std':
using namespace std;
// the second parameter is only valid
// when begin(C()) and end(C()) are valid
template<typename C,
typename=decltype(begin(std::declval<C>()),end(std::declval<C>()))
>
struct impl
{
using type = void; // only here impl
};
// explicitly disable conflicting types here
template<>
struct impl<std::string>;
}
// this uses the above to check for ::type,
// which only exists if begin/end are valid
// and there is no specialization to disable it
// (like in the std::string case)
template<class C,typename = typename supports_begin_end::impl<C>::type>
std::ostream& operator<<(std::ostream& out, const C& v) {
for(auto x : v) out<<x<<' ';
return out;
}
Существуют и другие типы, которые подходят для циклов, основанных на диапазонах. Не знаю, нужно ли их обнаруживать.
Здесь приведен обновленный живой пример, который определяет оба контейнера/типы, поддерживающие begin(v)
/end(v)
, а также типы, которые поддерживают v.begin()
/v.end()
.