I am trying to write a template function that will only accept std::vector
as argument. However what I have come up with works only for normal or lvalue parameters, but not for forwarding reference arguments.
The following code doesn't compile.
template <typename T, typename = typename std::enable_if< std::is_same<T, std::vector< typename T::value_type, typename T::allocator_type > >::value>::type >
int f(T && a) {
return a.size();
}
int main() {
std::vector<int> a;
f(a);
}
However if I replace parameter type of f
to be an lvalue reference or pass by value type as in:
template <typename T, typename = typename std::enable_if< std::is_same<T, std::vector< typename T::value_type, typename T::allocator_type > >::value>::type >
int f(T a) {
return a.size();
}
than it compiles.
Note that, I need to have argument of f a forwarding reference.
What am I missing?
If you want to only accept vectors, then your code can be simplified quite a bit. Instead of using SFINAE, you can just specify you want a std::vector
with any type of a parameters. That would look like
template <typename... Pack>
int f(std::vector<Pack...>const & a)
{
return a.size();
}
The reason your SFINAE approach doesnt work is that when you pass an lvalue to the function T
is deduced as a reference type. Reference types don't work like the type itself when it comes to doing things like
typename T::value_type
To fix that you need to remove the reference-ness of T
using std::remove_reference
. That would give you a function like
template <typename T, typename VecType = typename std::remove_reference<T>::type, typename = typename std::enable_if< std::is_same<VecType, std::vector< typename VecType::value_type, typename VecType::allocator_type > >::value>::type >
int f(T && a) {
return a.size();
}