I have the following templated code
#include <vector>
#include <array>
#include <iostream>
template<typename T1>
void foo(std::vector<T1> bar) {
std::cout << "GENERIC" << std::endl;
}
template<typename T1>
void foo(std::vector<std::vector<T1>> bar) {
std::cout << "SPECIFIC (vector)" << std::endl;
}
template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
std::cout << "SPECIFIC (array)" << std::endl;
}
int main() {
std::vector<std::vector<int>> a(2, std::vector<int> { 1, 2, 3});
std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});
foo(a);
foo(b);
}
which produces
SPECIFIC (vector)
GENERIC
I'm wondering why the vector-of-vector version is called with the specific template, but the vector-of-array version is called with the generic?
template<typename T1, size_t SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
std::cout << "SPECIFIC (array)" << std::endl;
}
You should use std::size_t
instead of int
.
run here
Edit :
Actually, your comments and my intuition about the code led me to dig into the topic. At first glance, a standard developer ( like me ) expect compiler to convert int
to std::size_t
(because they are both integral type and implicitly converting is very trivial) and select void foo(std::vector<std::array<T1, SIZE>> bar)
as best specialization. So while reading template argument deduction page i found this :
If a non-type template parameter is used in the parameter list, and the corresponding template argument is deduced, the type of the deduced template argument ( as specified in its enclosing template parameter list, meaning references are preserved) must match the type of the non-type template parameter exactly, except that cv-qualifiers are dropped, and except where the template argument is deduced from an array bound—in that case any integral type is allowed, even bool though it would always become true:
As always, of course, you must read few more times than once to understand what it means :)
So an interesting result comes out.
Already our desired specialization is not selected but if the compiler had been forced to select, it would be an error.
template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
std::cout << "SPECIFIC (array)" << std::endl;
}
int main() {
std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});
foo(b); // P = std::vector<std::array<int,(int)SIZE>
// A = std::vector<std::array<int,(unsigned_long)SIZE>>
// error: deduced non-type template argument does not have the same
// type as its corresponding template argument */
}
run code
Another interesting thing is :
If the non-type template argument had not been deduced, there would be no restriction which forces argument and template types to be same.
#include <vector>
#include <array>
#include <iostream>
template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
std::cout << "SPECIFIC (array)" << std::endl;
}
int main() {
std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});
foo<int,3>(b);
}
run code
I think this is simply due to one line from [temp.deduct.call]/4
In general, the deduction process attempts to find template argument values that will make the deduced A identical to A
To clarify, A
means the parameter, from [temp.deduct.call]/1
...template argument deduction with the type of the corresponding argument of the call (call it A)...
As has already been pointed out, changing template<typename T1, int SIZE>
to template<typename T1, size_t SIZE>
fixes the issue you are seeing. As stated in [temp.deduct.call]/4
, the compiler is looking to deduce an A
that is identical to A
. Since an std::array
has template arguments <class T, size_t N>
(from [array.syn]
), it's second parameter is in fact size_t
, not int
.
Therefore, for the template deduction, your generic function of template<typename T1>
is able to match exactly the type of A
, where-as your specialized template<typename T1, int SIZE>
is not an exact match. I believe MSVC is incorrect in its deduction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With