I am working on a class template for a signal processing library that is supposed to hold scalar samples or vectors of scalar samples (which is common in, e.g., frame-wise signal processing).
The class is essentially a facade for the std::vector
with some added convenience methods and members.
For scalar types, everything is fine. But I am running into trouble when I allow vectors as template arguments. Here is a minimum example of what I mean:
template <class T>
class Signal
{
public:
Signal() = default;
std::vector<T> samples;
friend std::ostream& operator<<(std::ostream& os, const Signal& obj)
{
for (const auto& x : obj.samples)
{
os << x << ",";
}
return os << std::endl;
}
}
I am obviously getting an error about a missing '<<' operator for a right-hand operand of type std::vector. What I want is to define different operators (and also some other methods not shown in the minimum example above) for scalar and vector-like template arguments.
I have done some research and learned about the concept of SFINAE, but I am having trouble connecting the dots.
Can anyone point me in the right direction? I feel like this should be a fairly common problem. Or am I going about this all wrong?
You might use overloads instead of SFINAE:
template <typename T>
std::ostream& print(std::ostream& os, const T& obj)
{
return os << obj;
}
template <typename T>
std::ostream& print(std::ostream& os, const std::vector<T>& v)
{
os << "{";
const char* sep = "";
for (const auto& e : v) {
os << sep;
print(os, e);
sep = ", ";
}
return os << "}";
}
template <class T>
class Signal
{
public:
Signal() = default;
std::vector<T> samples;
friend std::ostream& operator<<(std::ostream& os, const Signal& obj)
{
for (const auto& x : obj.samples)
{
print(os, x) << ",";
}
return os << std::endl;
}
};