You can make use of alias template that would sfinae out types without containing iterator type passed to your specialization e.g.:
#include <vector>
#include <array>
template <class>
struct without_iterator { };
template <class T>
struct X {
static constexpr bool value = false;
};
template <class T, class...>
using typer = T;
template <class T>
struct X<typer<T, typename T::iterator>> {
static constexpr bool value = true;
};
int main() {
static_assert(X<std::vector<int>>::value, "!");
static_assert(X<std::array<int, 4>>::value, "!");
static_assert(!X<without_iterator<int>>::value, "!");
static_assert(!X<int>::value, "!");
}
where X
is your CPPUNIT_NS::assertion_traits
[live demo]
To apply it to your solution:
template <class T, class...>
using typer = T;
namespace CPPUNIT_NS
{
template <class T> struct assertion_traits<typer<T, typename T::iterator>>
{
inline static bool equal(const T& left, const T& right)
{
return std::equal(left.begin(), left.end(), right.begin(), assertion_traits<decltype(*(left.begin()))>::equal);
}
inline static string toString(const T& vector)
// etc...
If you'd like you could also test for begin end existance to make sure interface of your T is as expected. You could even test if T comes from std namespace if you'd like (at least in some limited extend).
Edit:
The safer approach would be to stick to:
template <template <class...> class V, class... Ts>
struct X<typer<V<Ts...>, typename V<Ts...>::iterator>> {
static constexpr bool value = true;
};
even though it can't be applied to std::array
as using struct X<typer<T, typename T::iterator>>
might not be seen by the compiler as specialization of an X
template but the redefinition of X
(example)...