How can I use this function? (syntax)
template<typename T, typename = std::enable_if_t<std::is_array_v<T>>>
void foo(T&& a)
{
std::cout << a.size() << std::endl;
}
because this is error
std::array<std::string, 3> arr { "1", "2", "3" };
foo<std::array<std::string, 3>>(arr);
this error too
std::array<std::string, 3> arr { "1", "2", "3" };
foo<>(arr);
this error too
std::array<std::string, 3> arr { "1", "2", "3" };
foo<std::array<std::string, 3>, 3>(arr);
link: https://godbolt.org/z/ToMeGe5d5
CodePudding user response:
The function is constrained so that it accepts only built-in arrays as argument, not std::array
. std::is_array_v
tests only for built-in arrays.
Also, functions with forwarding references as function parameter (T&&
where T
is a template parameter) are not expected to have the corresponding type template argument (for T
) specified explicitly. So just drop the template argument list in the call completely. It is supposed to be deduced, otherwise the forwarding reference will not work as intended.
For example:
std::string arr[] = { "1", "2", "3" };
foo(arr);
But then the function specialization will fail to instantiate, because built-in arrays don't have members that can be referred to with the member access operator as in a.size()
. So the function is not usable at all. (I am not sure whether you made a mistake here reducing the actual function to an example or whether you are trying to write a function accepting std::array
yourself, in which case the other answers are giving good suggestions.)
CodePudding user response:
std::is_array_v<std::array<T, N>>
yields false
for any T
and N
. You need to create a custom type trait or simply write the function differently:
template<typename T, size_t N>
void foo(std::array<T, N> const& a)
{
std::cout << a.size() << std::endl;
}
or
template<class T>
struct is_std_array : std::false_type {};
template<class T, size_t N>
struct is_std_array<std::array<T, N>> : std::true_type {};
template<class T>
constexpr bool is_std_array_v = is_std_array<std::remove_cvref_t<T>>::value;
template<typename T, std::enable_if_t<is_std_array_v<T>, bool> = false>
void foo(T&& a)
{
std::cout << a.size() << std::endl;
}
See godbolt
CodePudding user response:
That function is (almost[1]) uncallable as written:
std::is_array_v
is onlytrue
for built-in C-style arrays. That isstd::is_array_v<int[10]>
istrue
, butstd::is_array_v<std::array<int, 10>>
isfalse
.- Built-in C-style arrays do not have a
size
member function.
That means that for any parameter type that will satisfy your type constraint, the body of the function will fail to compile.
You don't really need a type constraint though. You can just make your parameter a std::array
:
template<typename T, size_t N>
void foo(const std::array<T, N>& a)
{
std::cout << a.size() << std::endl;
}
int main()
{
std::array<int, 4> arr = {1, 2, 3, 4};
foo(arr); // prints 4
}
Or if you're trying to get the size of a built-in C-style array:
template<typename T, size_t N>
void foo(const T(&a)[N])
{
std::cout << N << std::endl;
}
int main()
{
int arr[] = {1, 2, 3, 4};
foo(arr); // prints 4
}
[1]: Technically foo<std::array<std::string, 3>&, void>(arr)
works, but that's just because you've implemented the type check in such a way that it can be worked around by supplying something in place of the default template argument.